blob: 3e0494293387d8865c5bf2865b5d75bfa12d0f3e [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
110 JSObject* boilerplate) {
111 StackLimitCheck check(isolate);
112 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000117 if (!maybe_result->ToObject(&result)) return maybe_result;
118 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 JSObject* copy = JSObject::cast(result);
120
121 // Deep copy local properties.
122 if (copy->HasFastProperties()) {
123 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 for (int i = 0; i < properties->length(); i++) {
125 Object* value = properties->get(i);
126 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 if (!maybe_result->ToObject(&result)) return maybe_result;
130 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000131 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 }
133 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000134 int nof = copy->map()->inobject_properties();
135 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000136 Object* value = copy->InObjectPropertyAt(i);
137 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 if (!maybe_result->ToObject(&result)) return maybe_result;
141 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000143 }
144 }
145 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000148 if (!maybe_result->ToObject(&result)) return maybe_result;
149 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 FixedArray* names = FixedArray::cast(result);
151 copy->GetLocalPropertyNames(names, 0);
152 for (int i = 0; i < names->length(); i++) {
153 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 // Only deep copy fields from the object literal expression.
158 // In particular, don't try to copy the length attribute of
159 // an array.
160 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 Object* value =
162 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
168 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000169 // Creating object copy for literals. No strict mode needed.
170 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 if (!maybe_result->ToObject(&result)) return maybe_result;
172 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 }
176
177 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000179 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000180 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000181 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000182 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000183 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 if (elements->map() == heap->fixed_cow_array_map()) {
185 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000186#ifdef DEBUG
187 for (int i = 0; i < elements->length(); i++) {
188 ASSERT(!elements->get(i)->IsJSObject());
189 }
190#endif
191 } else {
192 for (int i = 0; i < elements->length(); i++) {
193 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000194 ASSERT(value->IsSmi() ||
195 value->IsTheHole() ||
196 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 if (value->IsJSObject()) {
198 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
200 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000203 elements->set(i, result);
204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 }
206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000208 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000209 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 NumberDictionary* element_dictionary = copy->element_dictionary();
211 int capacity = element_dictionary->Capacity();
212 for (int i = 0; i < capacity; i++) {
213 Object* k = element_dictionary->KeyAt(i);
214 if (element_dictionary->IsKey(k)) {
215 Object* value = element_dictionary->ValueAt(i);
216 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000217 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
219 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220 if (!maybe_result->ToObject(&result)) return maybe_result;
221 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000222 element_dictionary->ValueAtPut(i, result);
223 }
224 }
225 }
226 break;
227 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000228 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000229 UNIMPLEMENTED();
230 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000231 case EXTERNAL_PIXEL_ELEMENTS:
232 case EXTERNAL_BYTE_ELEMENTS:
233 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
234 case EXTERNAL_SHORT_ELEMENTS:
235 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
236 case EXTERNAL_INT_ELEMENTS:
237 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
238 case EXTERNAL_FLOAT_ELEMENTS:
239 case EXTERNAL_DOUBLE_ELEMENTS:
240 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000241 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000242 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 }
244 return copy;
245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000251}
252
253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000254RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257}
258
259
ager@chromium.org236ad962008-09-25 09:45:57 +0000260static Handle<Map> ComputeObjectLiteralMap(
261 Handle<Context> context,
262 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000263 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 int properties_length = constant_properties->length();
266 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000270 for (int p = 0; p != properties_length; p += 2) {
271 Object* key = constant_properties->get(p);
272 uint32_t element_index = 0;
273 if (key->IsSymbol()) {
274 number_of_symbol_keys++;
275 } else if (key->ToArrayIndex(&element_index)) {
276 // An index key does not require space in the property backing store.
277 number_of_properties--;
278 } else {
279 // Bail out as a non-symbol non-index key makes caching impossible.
280 // ASSERT to make sure that the if condition after the loop is false.
281 ASSERT(number_of_symbol_keys != number_of_properties);
282 break;
283 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000285 // If we only have symbols and array indices among keys then we can
286 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 if ((number_of_symbol_keys == number_of_properties) &&
289 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000290 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<FixedArray> keys =
292 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000293 if (number_of_symbol_keys > 0) {
294 int index = 0;
295 for (int p = 0; p < properties_length; p += 2) {
296 Object* key = constant_properties->get(p);
297 if (key->IsSymbol()) {
298 keys->set(index++, key);
299 }
300 }
301 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000303 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 }
306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000307 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000309 Handle<Map>(context->object_function()->initial_map()),
310 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311}
312
313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
317 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319
320static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000322 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000323 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 bool should_have_fast_elements,
325 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000326 // Get the global context from the literals array. This is the
327 // context in which the function was created and we use the object
328 // function from this context to create the object literal. We do
329 // not use the object function from the current global context
330 // because this might be the object function from another context
331 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000332 Handle<Context> context =
333 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 // In case we have function literals, we want the object to be in
336 // slow properties mode for now. We don't go in the map cache because
337 // maps with constant functions can't be shared if the functions are
338 // not the same (which is the common case).
339 bool is_result_from_cache = false;
340 Handle<Map> map = has_function_literal
341 ? Handle<Map>(context->object_function()->initial_map())
342 : ComputeObjectLiteralMap(context,
343 constant_properties,
344 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000347
348 // Normalize the elements of the boilerplate to save space if needed.
349 if (!should_have_fast_elements) NormalizeElements(boilerplate);
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // Add the constant properties to the boilerplate.
352 int length = constant_properties->length();
353 bool should_transform =
354 !is_result_from_cache && boilerplate->HasFastProperties();
355 if (should_transform || has_function_literal) {
356 // Normalize the properties of object to avoid n^2 behavior
357 // when extending the object multiple properties. Indicate the number of
358 // properties to be added.
359 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
360 }
361
362 for (int index = 0; index < length; index +=2) {
363 Handle<Object> key(constant_properties->get(index+0), isolate);
364 Handle<Object> value(constant_properties->get(index+1), isolate);
365 if (value->IsFixedArray()) {
366 // The value contains the constant_properties of a
367 // simple object or array literal.
368 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
369 value = CreateLiteralBoilerplate(isolate, literals, array);
370 if (value.is_null()) return value;
371 }
372 Handle<Object> result;
373 uint32_t element_index = 0;
374 if (key->IsSymbol()) {
375 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
376 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000377 result = SetOwnElement(boilerplate,
378 element_index,
379 value,
380 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 Handle<String> name(String::cast(*key));
383 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 } else if (key->ToArrayIndex(&element_index)) {
388 // Array index (uint32).
389 result = SetOwnElement(boilerplate,
390 element_index,
391 value,
392 kNonStrictMode);
393 } else {
394 // Non-uint32 number.
395 ASSERT(key->IsNumber());
396 double num = key->Number();
397 char arr[100];
398 Vector<char> buffer(arr, ARRAY_SIZE(arr));
399 const char* str = DoubleToCString(num, buffer);
400 Handle<String> name =
401 isolate->factory()->NewStringFromAscii(CStrVector(str));
402 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
403 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 // If setting the property on the boilerplate throws an
406 // exception, the exception is converted to an empty handle in
407 // the handle based operations. In that case, we need to
408 // convert back to an exception.
409 if (result.is_null()) return result;
410 }
411
412 // Transform to fast properties if necessary. For object literals with
413 // containing function literals we defer this operation until after all
414 // computed properties have been assigned so that we can generate
415 // constant function properties.
416 if (should_transform && !has_function_literal) {
417 TransformToFastProperties(boilerplate,
418 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 }
420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000422}
423
424
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000425static const int kSmiOnlyLiteralMinimumLength = 1024;
426
427
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 Handle<FixedArray> literals,
431 Handle<FixedArray> elements) {
432 // Create the JSArray.
433 Handle<JSFunction> constructor(
434 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000437 if (elements->length() > kSmiOnlyLiteralMinimumLength) {
438 Handle<Map> smi_array_map = isolate->factory()->GetElementsTransitionMap(
439 Handle<JSObject>::cast(object),
440 FAST_SMI_ONLY_ELEMENTS);
441 HeapObject::cast(*object)->set_map(*smi_array_map);
442 }
443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 const bool is_cow =
445 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448
449 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 bool has_non_smi = false;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000451 if (is_cow) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000452 // Copy-on-write arrays must be shallow (and simple).
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000453 for (int i = 0; i < content->length(); i++) {
454 Object* current = content->get(i);
455 ASSERT(!current->IsFixedArray());
456 if (!current->IsSmi() && !current->IsTheHole()) {
457 has_non_smi = true;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000458 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000459 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000460#if DEBUG
461 for (int i = 0; i < content->length(); i++) {
462 ASSERT(!content->get(i)->IsFixedArray());
463 }
464#endif
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000465 } else {
466 for (int i = 0; i < content->length(); i++) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000467 Object* current = content->get(i);
468 if (current->IsFixedArray()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000469 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000471 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
472 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000474 if (result.is_null()) return result;
475 content->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 has_non_smi = true;
477 } else {
478 if (!current->IsSmi() && !current->IsTheHole()) {
479 has_non_smi = true;
480 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000481 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 }
483 }
484
485 // Set the elements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000486 Handle<JSArray> js_object(Handle<JSArray>::cast(object));
487 isolate->factory()->SetContent(js_object, content);
488
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000489 if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
490 isolate->factory()->EnsureCanContainNonSmiElements(js_object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000491 }
492
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000493 return object;
494}
495
496
497static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 Handle<FixedArray> literals,
500 Handle<FixedArray> array) {
501 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000504 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 return CreateObjectLiteralBoilerplate(isolate,
506 literals,
507 elements,
508 true,
509 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000510 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 return CreateObjectLiteralBoilerplate(isolate,
512 literals,
513 elements,
514 false,
515 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 default:
519 UNREACHABLE();
520 return Handle<Object>::null();
521 }
522}
523
524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000525RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000526 // Takes a FixedArray of elements containing the literal elements of
527 // the array literal and produces JSArray with those elements.
528 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000529 // which contains the context from which to get the Array function
530 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000532 ASSERT(args.length() == 3);
533 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000534 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 Handle<Object> object =
538 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *object);
543 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000547RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000549 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
555 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateObjectLiteralBoilerplate(isolate,
561 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000562 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 should_have_fast_elements,
564 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 if (boilerplate.is_null()) return Failure::Exception();
566 // Update the functions literal and return the boilerplate.
567 literals->set(literals_index, *boilerplate);
568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570}
571
572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000573RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000575 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
581 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000582
583 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 Handle<Object> boilerplate(literals->get(literals_index), isolate);
585 if (*boilerplate == isolate->heap()->undefined_value()) {
586 boilerplate = CreateObjectLiteralBoilerplate(isolate,
587 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000588 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 should_have_fast_elements,
590 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591 if (boilerplate.is_null()) return Failure::Exception();
592 // Update the functions literal and return the boilerplate.
593 literals->set(literals_index, *boilerplate);
594 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596}
597
598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000599RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 ASSERT(args.length() == 3);
602 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000603 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000604 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
621 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
628 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629 if (boilerplate.is_null()) return Failure::Exception();
630 // Update the functions literal and return the boilerplate.
631 literals->set(literals_index, *boilerplate);
632 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000633 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000635 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
642 ASSERT(args.length() == 2);
643 Object* handler = args[0];
644 Object* prototype = args[1];
645 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000646 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000647 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
648}
649
650
lrn@chromium.org34e60782011-09-15 07:25:40 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
652 ASSERT(args.length() == 4);
653 Object* handler = args[0];
654 Object* call_trap = args[1];
655 Object* construct_trap = args[2];
656 Object* prototype = args[3];
657 Object* used_prototype =
658 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
659 return isolate->heap()->AllocateJSFunctionProxy(
660 handler, call_trap, construct_trap, used_prototype);
661}
662
663
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
665 ASSERT(args.length() == 1);
666 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000667 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668}
669
670
lrn@chromium.org34e60782011-09-15 07:25:40 +0000671RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
672 ASSERT(args.length() == 1);
673 Object* obj = args[0];
674 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
675}
676
677
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000678RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
679 ASSERT(args.length() == 1);
680 CONVERT_CHECKED(JSProxy, proxy, args[0]);
681 return proxy->handler();
682}
683
684
lrn@chromium.org34e60782011-09-15 07:25:40 +0000685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
686 ASSERT(args.length() == 1);
687 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
688 return proxy->call_trap();
689}
690
691
692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
693 ASSERT(args.length() == 1);
694 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
695 return proxy->construct_trap();
696}
697
698
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
700 ASSERT(args.length() == 1);
701 CONVERT_CHECKED(JSProxy, proxy, args[0]);
702 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000703 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704}
705
706
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
708 HandleScope scope(isolate);
709 ASSERT(args.length() == 1);
710 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
711 ASSERT(weakmap->map()->inobject_properties() == 0);
712 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
713 weakmap->set_table(*table);
714 weakmap->set_next(Smi::FromInt(0));
715 return *weakmap;
716}
717
718
719RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
720 NoHandleAllocation ha;
721 ASSERT(args.length() == 2);
722 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000723 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
724 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000725}
726
727
728RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
729 HandleScope scope(isolate);
730 ASSERT(args.length() == 3);
731 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000732 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000733 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000734 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000735 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
736 weakmap->set_table(*new_table);
737 return *value;
738}
739
740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000741RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742 NoHandleAllocation ha;
743 ASSERT(args.length() == 1);
744 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000745 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 return JSObject::cast(obj)->class_name();
747}
748
ager@chromium.org7c537e22008-10-16 08:43:32 +0000749
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
751 NoHandleAllocation ha;
752 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000753 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
754 Object* obj = input_obj;
755 // We don't expect access checks to be needed on JSProxy objects.
756 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000757 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000758 if (obj->IsAccessCheckNeeded() &&
759 !isolate->MayNamedAccess(JSObject::cast(obj),
760 isolate->heap()->Proto_symbol(),
761 v8::ACCESS_GET)) {
762 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
763 return isolate->heap()->undefined_value();
764 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000765 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000766 } while (obj->IsJSObject() &&
767 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000768 return obj;
769}
770
771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000772RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 NoHandleAllocation ha;
774 ASSERT(args.length() == 2);
775 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
776 Object* O = args[0];
777 Object* V = args[1];
778 while (true) {
779 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 if (prototype->IsNull()) return isolate->heap()->false_value();
781 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 V = prototype;
783 }
784}
785
786
ager@chromium.org9085a012009-05-11 19:22:57 +0000787// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000788RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000789 NoHandleAllocation ha;
790 ASSERT(args.length() == 2);
791 CONVERT_CHECKED(JSObject, jsobject, args[0]);
792 CONVERT_CHECKED(JSObject, proto, args[1]);
793
794 // Sanity checks. The old prototype (that we are replacing) could
795 // theoretically be null, but if it is not null then check that we
796 // didn't already install a hidden prototype here.
797 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
798 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
799 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
800
801 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000802 Object* map_or_failure;
803 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
804 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
805 return maybe_map_or_failure;
806 }
807 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000808 Map* new_proto_map = Map::cast(map_or_failure);
809
lrn@chromium.org303ada72010-10-27 09:33:13 +0000810 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
811 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
812 return maybe_map_or_failure;
813 }
814 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000815 Map* new_map = Map::cast(map_or_failure);
816
817 // Set proto's prototype to be the old prototype of the object.
818 new_proto_map->set_prototype(jsobject->GetPrototype());
819 proto->set_map(new_proto_map);
820 new_proto_map->set_is_hidden_prototype();
821
822 // Set the object's prototype to proto.
823 new_map->set_prototype(proto);
824 jsobject->set_map(new_map);
825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000826 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000827}
828
829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000830RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000832 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000833 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000834 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835}
836
837
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838// Recursively traverses hidden prototypes if property is not found
839static void GetOwnPropertyImplementation(JSObject* obj,
840 String* name,
841 LookupResult* result) {
842 obj->LocalLookupRealNamedProperty(name, result);
843
844 if (!result->IsProperty()) {
845 Object* proto = obj->GetPrototype();
846 if (proto->IsJSObject() &&
847 JSObject::cast(proto)->map()->is_hidden_prototype())
848 GetOwnPropertyImplementation(JSObject::cast(proto),
849 name, result);
850 }
851}
852
853
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000854static bool CheckAccessException(LookupResult* result,
855 v8::AccessType access_type) {
856 if (result->type() == CALLBACKS) {
857 Object* callback = result->GetCallbackObject();
858 if (callback->IsAccessorInfo()) {
859 AccessorInfo* info = AccessorInfo::cast(callback);
860 bool can_access =
861 (access_type == v8::ACCESS_HAS &&
862 (info->all_can_read() || info->all_can_write())) ||
863 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
864 (access_type == v8::ACCESS_SET && info->all_can_write());
865 return can_access;
866 }
867 }
868
869 return false;
870}
871
872
873static bool CheckAccess(JSObject* obj,
874 String* name,
875 LookupResult* result,
876 v8::AccessType access_type) {
877 ASSERT(result->IsProperty());
878
879 JSObject* holder = result->holder();
880 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000882 while (true) {
883 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000885 // Access check callback denied the access, but some properties
886 // can have a special permissions which override callbacks descision
887 // (currently see v8::AccessControl).
888 break;
889 }
890
891 if (current == holder) {
892 return true;
893 }
894
895 current = JSObject::cast(current->GetPrototype());
896 }
897
898 // API callbacks can have per callback access exceptions.
899 switch (result->type()) {
900 case CALLBACKS: {
901 if (CheckAccessException(result, access_type)) {
902 return true;
903 }
904 break;
905 }
906 case INTERCEPTOR: {
907 // If the object has an interceptor, try real named properties.
908 // Overwrite the result to fetch the correct property later.
909 holder->LookupRealNamedProperty(name, result);
910 if (result->IsProperty()) {
911 if (CheckAccessException(result, access_type)) {
912 return true;
913 }
914 }
915 break;
916 }
917 default:
918 break;
919 }
920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 return false;
923}
924
925
926// TODO(1095): we should traverse hidden prototype hierachy as well.
927static bool CheckElementAccess(JSObject* obj,
928 uint32_t index,
929 v8::AccessType access_type) {
930 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 return false;
933 }
934
935 return true;
936}
937
938
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939// Enumerator used as indices into the array returned from GetOwnProperty
940enum PropertyDescriptorIndices {
941 IS_ACCESSOR_INDEX,
942 VALUE_INDEX,
943 GETTER_INDEX,
944 SETTER_INDEX,
945 WRITABLE_INDEX,
946 ENUMERABLE_INDEX,
947 CONFIGURABLE_INDEX,
948 DESCRIPTOR_SIZE
949};
950
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000951// Returns an array with the property description:
952// if args[1] is not a property on args[0]
953// returns undefined
954// if args[1] is a data property on args[0]
955// [false, value, Writeable, Enumerable, Configurable]
956// if args[1] is an accessor on args[0]
957// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000958RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000959 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 Heap* heap = isolate->heap();
961 HandleScope scope(isolate);
962 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
963 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000965 CONVERT_ARG_CHECKED(JSObject, obj, 0);
966 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000967
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000968 // This could be an element.
969 uint32_t index;
970 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 switch (obj->HasLocalElement(index)) {
972 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000974
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000975 case JSObject::STRING_CHARACTER_ELEMENT: {
976 // Special handling of string objects according to ECMAScript 5
977 // 15.5.5.2. Note that this might be a string object with elements
978 // other than the actual string value. This is covered by the
979 // subsequent cases.
980 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
981 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000982 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 elms->set(WRITABLE_INDEX, heap->false_value());
987 elms->set(ENUMERABLE_INDEX, heap->false_value());
988 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000989 return *desc;
990 }
991
992 case JSObject::INTERCEPTED_ELEMENT:
993 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000995 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000997 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 elms->set(WRITABLE_INDEX, heap->true_value());
999 elms->set(ENUMERABLE_INDEX, heap->true_value());
1000 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001001 return *desc;
1002 }
1003
1004 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001005 Handle<JSObject> holder = obj;
1006 if (obj->IsJSGlobalProxy()) {
1007 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001009 ASSERT(proto->IsJSGlobalObject());
1010 holder = Handle<JSObject>(JSObject::cast(proto));
1011 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001012 FixedArray* elements = FixedArray::cast(holder->elements());
1013 NumberDictionary* dictionary = NULL;
1014 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1015 dictionary = NumberDictionary::cast(elements->get(1));
1016 } else {
1017 dictionary = NumberDictionary::cast(elements);
1018 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 int entry = dictionary->FindEntry(index);
1020 ASSERT(entry != NumberDictionary::kNotFound);
1021 PropertyDetails details = dictionary->DetailsAt(entry);
1022 switch (details.type()) {
1023 case CALLBACKS: {
1024 // This is an accessor property with getter and/or setter.
1025 FixedArray* callbacks =
1026 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001028 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1029 elms->set(GETTER_INDEX, callbacks->get(0));
1030 }
1031 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1032 elms->set(SETTER_INDEX, callbacks->get(1));
1033 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001034 break;
1035 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001037 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001039 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001040 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001041 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001043 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001044 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001045 default:
1046 UNREACHABLE();
1047 break;
1048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1050 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001051 return *desc;
1052 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001053 }
1054 }
1055
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001056 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001058
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001059 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001061 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001062
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001063 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001065 }
1066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1068 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001069
1070 bool is_js_accessor = (result.type() == CALLBACKS) &&
1071 (result.GetCallbackObject()->IsFixedArray());
1072
1073 if (is_js_accessor) {
1074 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001076
1077 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1078 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1079 elms->set(GETTER_INDEX, structure->get(0));
1080 }
1081 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1082 elms->set(SETTER_INDEX, structure->get(1));
1083 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001084 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1086 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001087
1088 PropertyAttributes attrs;
1089 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001090 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001091 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1092 if (!maybe_value->ToObject(&value)) return maybe_value;
1093 }
1094 elms->set(VALUE_INDEX, value);
1095 }
1096
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097 return *desc;
1098}
1099
1100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001102 ASSERT(args.length() == 1);
1103 CONVERT_CHECKED(JSObject, obj, args[0]);
1104 return obj->PreventExtensions();
1105}
1106
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001108RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001109 ASSERT(args.length() == 1);
1110 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001111 if (obj->IsJSGlobalProxy()) {
1112 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001114 ASSERT(proto->IsJSGlobalObject());
1115 obj = JSObject::cast(proto);
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001124 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1125 CONVERT_ARG_CHECKED(String, pattern, 1);
1126 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001127 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1128 if (result.is_null()) return Failure::Exception();
1129 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130}
1131
1132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001133RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001136 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138}
1139
1140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 ASSERT(args.length() == 1);
1143 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001144 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146}
1147
1148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001149RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 ASSERT(args.length() == 2);
1151 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001153 int index = field->value();
1154 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1155 InstanceType type = templ->map()->instance_type();
1156 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1157 type == OBJECT_TEMPLATE_INFO_TYPE);
1158 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001159 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001160 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1161 } else {
1162 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1163 }
1164 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165}
1166
1167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001168RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001169 ASSERT(args.length() == 1);
1170 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001171 Map* old_map = object->map();
1172 bool needs_access_checks = old_map->is_access_check_needed();
1173 if (needs_access_checks) {
1174 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001175 Object* new_map;
1176 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1177 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1178 }
ager@chromium.org32912102009-01-16 10:38:43 +00001179
1180 Map::cast(new_map)->set_is_access_check_needed(false);
1181 object->set_map(Map::cast(new_map));
1182 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001183 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001188 ASSERT(args.length() == 1);
1189 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001190 Map* old_map = object->map();
1191 if (!old_map->is_access_check_needed()) {
1192 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001193 Object* new_map;
1194 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1195 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1196 }
ager@chromium.org32912102009-01-16 10:38:43 +00001197
1198 Map::cast(new_map)->set_is_access_check_needed(true);
1199 object->set_map(Map::cast(new_map));
1200 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001202}
1203
1204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001205static Failure* ThrowRedeclarationError(Isolate* isolate,
1206 const char* type,
1207 Handle<String> name) {
1208 HandleScope scope(isolate);
1209 Handle<Object> type_handle =
1210 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211 Handle<Object> args[2] = { type_handle, name };
1212 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1214 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215}
1216
1217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001218RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001219 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001220 HandleScope scope(isolate);
1221 Handle<GlobalObject> global = Handle<GlobalObject>(
1222 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223
ager@chromium.org3811b432009-10-28 14:53:37 +00001224 Handle<Context> context = args.at<Context>(0);
1225 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001226 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 // Traverse the name/value pairs and set the properties.
1229 int length = pairs->length();
1230 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234
1235 // We have to declare a global const property. To capture we only
1236 // assign to it when evaluating the assignment for "const x =
1237 // <expr>" the initial value is the hole.
1238 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001239 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 if (value->IsUndefined() || is_const_property) {
1241 // Lookup the property in the global object, and don't set the
1242 // value of the variable if the property is already there.
1243 LookupResult lookup;
1244 global->Lookup(*name, &lookup);
1245 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 // We found an existing property. Unless it was an interceptor
1247 // that claims the property is absent, skip this declaration.
1248 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 continue;
1250 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001251 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1252 if (attributes != ABSENT) {
1253 continue;
1254 }
1255 // Fall-through and introduce the absent property by using
1256 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001259 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001261 Handle<SharedFunctionInfo> shared =
1262 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1265 context,
1266 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 value = function;
1268 }
1269
1270 LookupResult lookup;
1271 global->LocalLookup(*name, &lookup);
1272
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 // Compute the property attributes. According to ECMA-262, section
1274 // 13, page 71, the property must be read-only and
1275 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1276 // property as read-only, so we don't either.
1277 int attr = NONE;
1278 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1279 attr |= DONT_DELETE;
1280 }
1281 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1282 if (is_const_property || (is_native && is_function_declaration)) {
1283 attr |= READ_ONLY;
1284 }
1285
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001286 // Safari does not allow the invocation of callback setters for
1287 // function declarations. To mimic this behavior, we do not allow
1288 // the invocation of setters for function values. This makes a
1289 // difference for global functions with the same names as event
1290 // handlers such as "function onload() {}". Firefox does call the
1291 // onload setter in those case and Safari does not. We follow
1292 // Safari for compatibility.
1293 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001294 // Do not change DONT_DELETE to false from true.
1295 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001296 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001297 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001298 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 RETURN_IF_EMPTY_HANDLE(isolate,
1301 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001302 name,
1303 value,
1304 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001306 StrictModeFlag strict_mode =
1307 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1308 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 RETURN_IF_EMPTY_HANDLE(isolate,
1310 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001311 name,
1312 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001314 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 }
1316 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 ASSERT(!isolate->has_pending_exception());
1319 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320}
1321
1322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001323RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001325 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 // Declarations are always made in a function or global context. In the
1328 // case of eval code, the context passed is the context of the caller,
1329 // which may be some nested context and not the declaration context.
1330 RUNTIME_ASSERT(args[0]->IsContext());
1331 Handle<Context> context(Context::cast(args[0])->declaration_context());
1332
ager@chromium.org7c537e22008-10-16 08:43:32 +00001333 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001334 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001335 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001336 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 int index;
1339 PropertyAttributes attributes;
1340 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001341 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001342 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001343 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001346 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1348 // Functions are not read-only.
1349 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1350 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 }
1353
1354 // Initialize it if necessary.
1355 if (*initial_value != NULL) {
1356 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 ASSERT(holder.is_identical_to(context));
1358 if (((attributes & READ_ONLY) == 0) ||
1359 context->get(index)->IsTheHole()) {
1360 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
1362 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 // Slow case: The property is in the context extension object of a
1364 // function context or the global object of a global context.
1365 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001366 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001367 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001368 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 }
1370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001373 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 // "declared" in the function context's extension context or as a
1375 // property of the the global object.
1376 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001377 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001379 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001380 // Context extension objects are allocated lazily.
1381 ASSERT(context->IsFunctionContext());
1382 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001386 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
ager@chromium.org7c537e22008-10-16 08:43:32 +00001388 // Declare the property by setting it to the initial value if provided,
1389 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1390 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001392 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001393 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001394 // Declaring a const context slot is a conflicting declaration if
1395 // there is a callback with that name in a prototype. It is
1396 // allowed to introduce const variables in
1397 // JSContextExtensionObjects. They are treated specially in
1398 // SetProperty and no setters are invoked for those since they are
1399 // not real JSObjects.
1400 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 !object->IsJSContextExtensionObject()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001402 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001404 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001406 }
1407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001408 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001410 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 }
1412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414}
1415
1416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001417RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 // args[0] == name
1420 // args[1] == strict_mode
1421 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // Determine if we need to assign to the variable if it already
1424 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001425 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1426 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427
1428 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001430 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // According to ECMA-262, section 12.2, page 62, the property must
1435 // not be deletable.
1436 PropertyAttributes attributes = DONT_DELETE;
1437
1438 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001439 // there, there is a property with this name in the prototype chain.
1440 // We follow Safari and Firefox behavior and only set the property
1441 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001443 // Note that objects can have hidden prototypes, so we need to traverse
1444 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 Object* object = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 while (object->IsJSObject() &&
1448 JSObject::cast(object)->map()->is_hidden_prototype()) {
1449 JSObject* raw_holder = JSObject::cast(object);
1450 raw_holder->LocalLookup(*name, &lookup);
1451 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1452 HandleScope handle_scope(isolate);
1453 Handle<JSObject> holder(raw_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 // Update the raw pointer in case it's changed due to GC.
1456 raw_holder = *holder;
1457 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1458 // Found an interceptor that's not read only.
1459 if (assign) {
1460 return raw_holder->SetProperty(
1461 &lookup, *name, args[2], attributes, strict_mode);
1462 } else {
1463 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001464 }
1465 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001466 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468 }
1469
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001470 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 if (assign) {
1473 return global->SetProperty(*name, args[2], attributes, strict_mode);
1474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 // All constants are declared with an initial value. The name
1481 // of the constant is the first argument and the initial value
1482 // is the second.
1483 RUNTIME_ASSERT(args.length() == 2);
1484 CONVERT_ARG_CHECKED(String, name, 0);
1485 Handle<Object> value = args.at<Object>(1);
1486
1487 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
1490 // According to ECMA-262, section 12.2, page 62, the property must
1491 // not be deletable. Since it's a const, it must be READ_ONLY too.
1492 PropertyAttributes attributes =
1493 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1494
1495 // Lookup the property locally in the global object. If it isn't
1496 // there, we add the property and take special precautions to always
1497 // add it as a local property even in case of callbacks in the
1498 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001499 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 LookupResult lookup;
1501 global->LocalLookup(*name, &lookup);
1502 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001503 return global->SetLocalPropertyIgnoreAttributes(*name,
1504 *value,
1505 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 }
1507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001511 HandleScope handle_scope(isolate);
1512 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001514 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 // property through an interceptor and only do it if it's
1516 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001517 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001518 RETURN_IF_EMPTY_HANDLE(isolate,
1519 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001520 name,
1521 value,
1522 attributes,
1523 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 return *value;
1525 }
1526
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 // constant. For now, we determine this by checking if the
1529 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 PropertyType type = lookup.type();
1532 if (type == FIELD) {
1533 FixedArray* properties = global->properties();
1534 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 properties->set(index, *value);
1537 }
1538 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1540 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001541 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 }
1543 } else {
1544 // Ignore re-initialization of constants that have already been
1545 // assigned a function value.
1546 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1547 }
1548
1549 // Use the set value as the result of the operation.
1550 return *value;
1551}
1552
1553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001554RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 ASSERT(args.length() == 3);
1557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001561 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 RUNTIME_ASSERT(args[1]->IsContext());
1563 Handle<Context> context(Context::cast(args[1])->declaration_context());
1564
1565 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
1567 int index;
1568 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001569 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001570 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001571 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001572 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 ASSERT(holder->IsContext());
1576 // Property was found in a context. Perform the assignment if we
1577 // found some non-constant or an uninitialized constant.
1578 Handle<Context> context = Handle<Context>::cast(holder);
1579 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1580 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
1582 return *value;
1583 }
1584
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001585 // The property could not be found, we introduce it as a property of the
1586 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001587 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001588 Handle<JSObject> global = Handle<JSObject>(
1589 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001590 // Strict mode not needed (const disallowed in strict mode).
1591 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001592 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001593 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001594 return *value;
1595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001597 // The property was present in some function's context extension object,
1598 // as a property on the subject of a with, or as a property of the global
1599 // object.
1600 //
1601 // In most situations, eval-introduced consts should still be present in
1602 // the context extension object. However, because declaration and
1603 // initialization are separate, the property might have been deleted
1604 // before we reach the initialization point.
1605 //
1606 // Example:
1607 //
1608 // function f() { eval("delete x; const x;"); }
1609 //
1610 // In that case, the initialization behaves like a normal assignment.
1611 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 if (*object == context->extension()) {
1614 // This is the property that was introduced by the const declaration.
1615 // Set it if it hasn't been set before. NOTE: We cannot use
1616 // GetProperty() to get the current value as it 'unholes' the value.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001617 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001618 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 ASSERT(lookup.IsProperty()); // the property was declared
1620 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1621
1622 PropertyType type = lookup.type();
1623 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001625 int index = lookup.GetFieldIndex();
1626 if (properties->get(index)->IsTheHole()) {
1627 properties->set(index, *value);
1628 }
1629 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001630 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1631 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001632 }
1633 } else {
1634 // We should not reach here. Any real, named property should be
1635 // either a field or a dictionary slot.
1636 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 }
1638 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001639 // The property was found on some other object. Set it if it is not a
1640 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001641 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 return *value;
1650}
1651
1652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001653RUNTIME_FUNCTION(MaybeObject*,
1654 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001655 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001656 ASSERT(args.length() == 2);
1657 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001658 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001659 if (object->HasFastProperties()) {
1660 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1661 }
1662 return *object;
1663}
1664
1665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
1667 ASSERT(args.length() == 1);
1668 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001669 if (object->HasFastSmiOnlyElements()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
1671 Map* map;
1672 if (!maybe_map->To<Map>(&map)) return maybe_map;
1673 object->set_map(Map::cast(map));
1674 }
1675 return *object;
1676}
1677
1678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001679RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001681 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001682 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1683 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001684 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001685 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001686 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001687 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001688 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001689 RUNTIME_ASSERT(index >= 0);
1690 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001692 Handle<Object> result = RegExpImpl::Exec(regexp,
1693 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001694 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001695 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001696 if (result.is_null()) return Failure::Exception();
1697 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698}
1699
1700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001701RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001702 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001703 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001704 if (elements_count < 0 ||
1705 elements_count > FixedArray::kMaxLength ||
1706 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001708 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709 Object* new_object;
1710 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1713 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001714 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1716 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1718 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 {
1720 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001724 }
1725 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001727 array->set_elements(elements);
1728 array->set_length(Smi::FromInt(elements_count));
1729 // Write in-object properties after the length of the array.
1730 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1731 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1732 return array;
1733}
1734
1735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001736RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001737 AssertNoAllocation no_alloc;
1738 ASSERT(args.length() == 5);
1739 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1740 CONVERT_CHECKED(String, source, args[1]);
1741
1742 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001744
1745 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001747
1748 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001750
1751 Map* map = regexp->map();
1752 Object* constructor = map->constructor();
1753 if (constructor->IsJSFunction() &&
1754 JSFunction::cast(constructor)->initial_map() == map) {
1755 // If we still have the original map, set in-object properties directly.
1756 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1757 // TODO(lrn): Consider skipping write barrier on booleans as well.
1758 // Both true and false should be in oldspace at all times.
1759 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1760 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1761 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1762 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1763 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001765 return regexp;
1766 }
1767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001769 PropertyAttributes final =
1770 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1771 PropertyAttributes writable =
1772 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001774 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001776 source,
1777 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001780 global,
1781 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001782 ASSERT(!result->IsFailure());
1783 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001785 ignoreCase,
1786 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001787 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001789 multiline,
1790 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791 ASSERT(!result->IsFailure());
1792 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001794 Smi::FromInt(0),
1795 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001796 ASSERT(!result->IsFailure());
1797 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 return regexp;
1799}
1800
1801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001802RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001804 ASSERT(args.length() == 1);
1805 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1806 // This is necessary to enable fast checks for absence of elements
1807 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001809 return Smi::FromInt(0);
1810}
1811
1812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1814 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001815 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001816 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1818 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1819 Handle<JSFunction> optimized =
1820 isolate->factory()->NewFunction(key,
1821 JS_OBJECT_TYPE,
1822 JSObject::kHeaderSize,
1823 code,
1824 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001825 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001826 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001827 return optimized;
1828}
1829
1830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001833 ASSERT(args.length() == 1);
1834 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1835
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001836 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1837 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1838 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1839 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1840 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1841 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1842 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001843
1844 return *holder;
1845}
1846
1847
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1849 NoHandleAllocation handle_free;
1850 ASSERT(args.length() == 1);
1851 CONVERT_CHECKED(JSFunction, function, args[0]);
1852 SharedFunctionInfo* shared = function->shared();
1853 if (shared->native() || shared->strict_mode()) {
1854 return isolate->heap()->undefined_value();
1855 }
1856 // Returns undefined for strict or native functions, or
1857 // the associated global receiver for "normal" functions.
1858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001860 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001861 return global_context->global()->global_receiver();
1862}
1863
1864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001865RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 ASSERT(args.length() == 4);
1868 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001869 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 Handle<String> pattern = args.at<String>(2);
1871 Handle<String> flags = args.at<String>(3);
1872
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001873 // Get the RegExp function from the context in the literals array.
1874 // This is the RegExp function from the context in which the
1875 // function was created. We do not use the RegExp function from the
1876 // current global context because this might be the RegExp function
1877 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001878 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001879 Handle<JSFunction>(
1880 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001881 // Compute the regular expression literal.
1882 bool has_pending_exception;
1883 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001884 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1885 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 return Failure::Exception();
1889 }
1890 literals->set(index, *regexp);
1891 return *regexp;
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 NoHandleAllocation ha;
1897 ASSERT(args.length() == 1);
1898
1899 CONVERT_CHECKED(JSFunction, f, args[0]);
1900 return f->shared()->name();
1901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001905 NoHandleAllocation ha;
1906 ASSERT(args.length() == 2);
1907
1908 CONVERT_CHECKED(JSFunction, f, args[0]);
1909 CONVERT_CHECKED(String, name, args[1]);
1910 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001912}
1913
1914
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001915RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1916 NoHandleAllocation ha;
1917 ASSERT(args.length() == 1);
1918 CONVERT_CHECKED(JSFunction, f, args[0]);
1919 return isolate->heap()->ToBoolean(
1920 f->shared()->name_should_print_as_anonymous());
1921}
1922
1923
1924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1);
1927 CONVERT_CHECKED(JSFunction, f, args[0]);
1928 f->shared()->set_name_should_print_as_anonymous(true);
1929 return isolate->heap()->undefined_value();
1930}
1931
1932
whesse@chromium.org7b260152011-06-20 15:33:18 +00001933RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1934 HandleScope scope(isolate);
1935 ASSERT(args.length() == 1);
1936
1937 CONVERT_CHECKED(JSFunction, fun, args[0]);
1938 fun->shared()->set_bound(true);
1939 return isolate->heap()->undefined_value();
1940}
1941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001942RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001943 NoHandleAllocation ha;
1944 ASSERT(args.length() == 1);
1945
1946 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947 Object* obj = f->RemovePrototype();
1948 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001950 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001951}
1952
1953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 ASSERT(args.length() == 1);
1957
1958 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1960 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961
1962 return *GetScriptWrapper(Handle<Script>::cast(script));
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
1971 return f->shared()->GetSourceCode();
1972}
1973
1974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001975RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 NoHandleAllocation ha;
1977 ASSERT(args.length() == 1);
1978
1979 CONVERT_CHECKED(JSFunction, fun, args[0]);
1980 int pos = fun->shared()->start_position();
1981 return Smi::FromInt(pos);
1982}
1983
1984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001986 ASSERT(args.length() == 2);
1987
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001989 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1990
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001991 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1992
1993 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001994 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 2);
2001
2002 CONVERT_CHECKED(JSFunction, fun, args[0]);
2003 CONVERT_CHECKED(String, name, args[1]);
2004 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 NoHandleAllocation ha;
2011 ASSERT(args.length() == 2);
2012
2013 CONVERT_CHECKED(JSFunction, fun, args[0]);
2014 CONVERT_CHECKED(Smi, length, args[1]);
2015 fun->shared()->set_length(length->value());
2016 return length;
2017}
2018
2019
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002020// Creates a local, readonly, property called length with the correct
2021// length (when read by the user). This effectively overwrites the
2022// interceptor used to normally provide the length.
2023RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2024 NoHandleAllocation ha;
2025 ASSERT(args.length() == 2);
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(Smi, length, args[1]);
2028 MaybeObject* maybe_name =
2029 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2030 String* name;
2031 if (!maybe_name->To(&name)) return maybe_name;
2032 PropertyAttributes attr =
2033 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2034 return fun->AddProperty(name, length, attr, kNonStrictMode);
2035}
2036
2037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002038RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 ASSERT(args.length() == 2);
2041
2042 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002043 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002044 Object* obj;
2045 { MaybeObject* maybe_obj =
2046 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2047 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2048 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 return args[0]; // return TOS
2050}
2051
2052
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002053RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2054 NoHandleAllocation ha;
2055 RUNTIME_ASSERT(args.length() == 1);
2056 CONVERT_CHECKED(JSFunction, function, args[0]);
2057
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062
2063 if (function->HasFastProperties()) {
2064 // Construct a new field descriptor with updated attributes.
2065 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2066 int index = instance_desc->Search(name);
2067 ASSERT(index != DescriptorArray::kNotFound);
2068 PropertyDetails details(instance_desc->GetDetails(index));
2069 CallbacksDescriptor new_desc(name,
2070 instance_desc->GetValue(index),
2071 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2072 details.index());
2073 // Construct a new field descriptors array containing the new descriptor.
2074 Object* descriptors_unchecked;
2075 { MaybeObject* maybe_descriptors_unchecked =
2076 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2077 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2078 return maybe_descriptors_unchecked;
2079 }
2080 }
2081 DescriptorArray* new_descriptors =
2082 DescriptorArray::cast(descriptors_unchecked);
2083 // Create a new map featuring the new field descriptors array.
2084 Object* map_unchecked;
2085 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2086 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2087 return maybe_map_unchecked;
2088 }
2089 }
2090 Map* new_map = Map::cast(map_unchecked);
2091 new_map->set_instance_descriptors(new_descriptors);
2092 function->set_map(new_map);
2093 } else { // Dictionary properties.
2094 // Directly manipulate the property details.
2095 int entry = function->property_dictionary()->FindEntry(name);
2096 ASSERT(entry != StringDictionary::kNotFound);
2097 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2098 PropertyDetails new_details(
2099 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2100 details.type(),
2101 details.index());
2102 function->property_dictionary()->DetailsAtPut(entry, new_details);
2103 }
2104 return function;
2105}
2106
2107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002108RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002109 NoHandleAllocation ha;
2110 ASSERT(args.length() == 1);
2111
2112 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002113 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002114}
2115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002117RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002118 NoHandleAllocation ha;
2119 ASSERT(args.length() == 1);
2120
2121 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002122 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002123}
2124
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002126RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002127 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002128 ASSERT(args.length() == 2);
2129
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002130 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002131 Handle<Object> code = args.at<Object>(1);
2132
2133 Handle<Context> context(target->context());
2134
2135 if (!code->IsNull()) {
2136 RUNTIME_ASSERT(code->IsJSFunction());
2137 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002138 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002139
2140 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141 return Failure::Exception();
2142 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143 // Since we don't store the source for this we should never
2144 // optimize this.
2145 shared->code()->set_optimizable(false);
2146
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002147 // Set the code, scope info, formal parameter count,
2148 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002149 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002150 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002151 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002152 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002155 // Set the source code of the target function to undefined.
2156 // SetCode is only used for built-in constructors like String,
2157 // Array, and Object, and some web code
2158 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002159 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002160 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002161 // Clear the optimization hints related to the compiled code as these are no
2162 // longer valid when the code is overwritten.
2163 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 context = Handle<Context>(fun->context());
2165
2166 // Make sure we get a fresh copy of the literal vector to avoid
2167 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002168 int number_of_literals = fun->NumberOfLiterals();
2169 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002170 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002171 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002172 // Insert the object, regexp and array functions in the literals
2173 // array prefix. These are the functions that will be used when
2174 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002175 literals->set(JSFunction::kLiteralGlobalContextIndex,
2176 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002178 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002180
2181 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2182 isolate->logger()->LogExistingFunction(
2183 shared, Handle<Code>(shared->code()));
2184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185 }
2186
2187 target->set_context(*context);
2188 return *target;
2189}
2190
2191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002192RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002193 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002194 ASSERT(args.length() == 2);
2195 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002196 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002197 RUNTIME_ASSERT(num >= 0);
2198 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002200}
2201
2202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2204 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002205 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002206 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002207 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002208 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002209 }
2210 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002212}
2213
2214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002215RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 NoHandleAllocation ha;
2217 ASSERT(args.length() == 2);
2218
2219 CONVERT_CHECKED(String, subject, args[0]);
2220 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002221 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002223 uint32_t i = 0;
2224 if (index->IsSmi()) {
2225 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002227 i = value;
2228 } else {
2229 ASSERT(index->IsHeapNumber());
2230 double value = HeapNumber::cast(index)->value();
2231 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002232 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002233
2234 // Flatten the string. If someone wants to get a char at an index
2235 // in a cons string, it is likely that more indices will be
2236 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002237 Object* flat;
2238 { MaybeObject* maybe_flat = subject->TryFlatten();
2239 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2240 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 subject = String::cast(flat);
2242
2243 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 }
2246
2247 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002248}
2249
2250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002251RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252 NoHandleAllocation ha;
2253 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255}
2256
lrn@chromium.org25156de2010-04-06 13:10:27 +00002257
2258class FixedArrayBuilder {
2259 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002260 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2261 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002262 length_(0),
2263 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 // Require a non-zero initial size. Ensures that doubling the size to
2265 // extend the array will work.
2266 ASSERT(initial_capacity > 0);
2267 }
2268
2269 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2270 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002271 length_(0),
2272 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002273 // Require a non-zero initial size. Ensures that doubling the size to
2274 // extend the array will work.
2275 ASSERT(backing_store->length() > 0);
2276 }
2277
2278 bool HasCapacity(int elements) {
2279 int length = array_->length();
2280 int required_length = length_ + elements;
2281 return (length >= required_length);
2282 }
2283
2284 void EnsureCapacity(int elements) {
2285 int length = array_->length();
2286 int required_length = length_ + elements;
2287 if (length < required_length) {
2288 int new_length = length;
2289 do {
2290 new_length *= 2;
2291 } while (new_length < required_length);
2292 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002293 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 array_->CopyTo(0, *extended_array, 0, length_);
2295 array_ = extended_array;
2296 }
2297 }
2298
2299 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002300 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002301 ASSERT(length_ < capacity());
2302 array_->set(length_, value);
2303 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002304 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 }
2306
2307 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002308 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 ASSERT(length_ < capacity());
2310 array_->set(length_, value);
2311 length_++;
2312 }
2313
2314 Handle<FixedArray> array() {
2315 return array_;
2316 }
2317
2318 int length() {
2319 return length_;
2320 }
2321
2322 int capacity() {
2323 return array_->length();
2324 }
2325
2326 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002327 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 result_array->set_length(Smi::FromInt(length_));
2329 return result_array;
2330 }
2331
2332 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002333 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002334 target_array->set_length(Smi::FromInt(length_));
2335 return target_array;
2336 }
2337
2338 private:
2339 Handle<FixedArray> array_;
2340 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002341 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002342};
2343
2344
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002345// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346const int kStringBuilderConcatHelperLengthBits = 11;
2347const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002348
2349template <typename schar>
2350static inline void StringBuilderConcatHelper(String*,
2351 schar*,
2352 FixedArray*,
2353 int);
2354
lrn@chromium.org25156de2010-04-06 13:10:27 +00002355typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2356 StringBuilderSubstringLength;
2357typedef BitField<int,
2358 kStringBuilderConcatHelperLengthBits,
2359 kStringBuilderConcatHelperPositionBits>
2360 StringBuilderSubstringPosition;
2361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002362
2363class ReplacementStringBuilder {
2364 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 ReplacementStringBuilder(Heap* heap,
2366 Handle<String> subject,
2367 int estimated_part_count)
2368 : heap_(heap),
2369 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002370 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002372 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373 // Require a non-zero initial size. Ensures that doubling the size to
2374 // extend the array will work.
2375 ASSERT(estimated_part_count > 0);
2376 }
2377
lrn@chromium.org25156de2010-04-06 13:10:27 +00002378 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2379 int from,
2380 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002381 ASSERT(from >= 0);
2382 int length = to - from;
2383 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 if (StringBuilderSubstringLength::is_valid(length) &&
2385 StringBuilderSubstringPosition::is_valid(from)) {
2386 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2387 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002388 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002390 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002391 builder->Add(Smi::FromInt(-length));
2392 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002394 }
2395
2396
2397 void EnsureCapacity(int elements) {
2398 array_builder_.EnsureCapacity(elements);
2399 }
2400
2401
2402 void AddSubjectSlice(int from, int to) {
2403 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 }
2406
2407
2408 void AddString(Handle<String> string) {
2409 int length = string->length();
2410 ASSERT(length > 0);
2411 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002412 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002413 is_ascii_ = false;
2414 }
2415 IncrementCharacterCount(length);
2416 }
2417
2418
2419 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002421 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 }
2423
2424 Handle<String> joined_string;
2425 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002426 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 char* char_buffer = seq->GetChars();
2429 StringBuilderConcatHelper(*subject_,
2430 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002431 *array_builder_.array(),
2432 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002433 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 } else {
2435 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002436 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 uc16* char_buffer = seq->GetChars();
2439 StringBuilderConcatHelper(*subject_,
2440 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002441 *array_builder_.array(),
2442 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002443 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445 return joined_string;
2446 }
2447
2448
2449 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002450 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 V8::FatalProcessOutOfMemory("String.replace result too large.");
2452 }
2453 character_count_ += by;
2454 }
2455
lrn@chromium.org25156de2010-04-06 13:10:27 +00002456 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002457 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002458 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002459
lrn@chromium.org25156de2010-04-06 13:10:27 +00002460 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2462 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464
2465
ager@chromium.org04921a82011-06-27 13:21:41 +00002466 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2467 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
2470
2471 void AddElement(Object* element) {
2472 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 ASSERT(array_builder_.capacity() > array_builder_.length());
2474 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 }
2476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002477 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 int character_count_;
2481 bool is_ascii_;
2482};
2483
2484
2485class CompiledReplacement {
2486 public:
2487 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002488 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489
2490 void Compile(Handle<String> replacement,
2491 int capture_count,
2492 int subject_length);
2493
2494 void Apply(ReplacementStringBuilder* builder,
2495 int match_from,
2496 int match_to,
2497 Handle<JSArray> last_match_info);
2498
2499 // Number of distinct parts of the replacement pattern.
2500 int parts() {
2501 return parts_.length();
2502 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002503
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002504 bool simple_hint() {
2505 return simple_hint_;
2506 }
2507
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002508 private:
2509 enum PartType {
2510 SUBJECT_PREFIX = 1,
2511 SUBJECT_SUFFIX,
2512 SUBJECT_CAPTURE,
2513 REPLACEMENT_SUBSTRING,
2514 REPLACEMENT_STRING,
2515
2516 NUMBER_OF_PART_TYPES
2517 };
2518
2519 struct ReplacementPart {
2520 static inline ReplacementPart SubjectMatch() {
2521 return ReplacementPart(SUBJECT_CAPTURE, 0);
2522 }
2523 static inline ReplacementPart SubjectCapture(int capture_index) {
2524 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2525 }
2526 static inline ReplacementPart SubjectPrefix() {
2527 return ReplacementPart(SUBJECT_PREFIX, 0);
2528 }
2529 static inline ReplacementPart SubjectSuffix(int subject_length) {
2530 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2531 }
2532 static inline ReplacementPart ReplacementString() {
2533 return ReplacementPart(REPLACEMENT_STRING, 0);
2534 }
2535 static inline ReplacementPart ReplacementSubString(int from, int to) {
2536 ASSERT(from >= 0);
2537 ASSERT(to > from);
2538 return ReplacementPart(-from, to);
2539 }
2540
2541 // If tag <= 0 then it is the negation of a start index of a substring of
2542 // the replacement pattern, otherwise it's a value from PartType.
2543 ReplacementPart(int tag, int data)
2544 : tag(tag), data(data) {
2545 // Must be non-positive or a PartType value.
2546 ASSERT(tag < NUMBER_OF_PART_TYPES);
2547 }
2548 // Either a value of PartType or a non-positive number that is
2549 // the negation of an index into the replacement string.
2550 int tag;
2551 // The data value's interpretation depends on the value of tag:
2552 // tag == SUBJECT_PREFIX ||
2553 // tag == SUBJECT_SUFFIX: data is unused.
2554 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2555 // tag == REPLACEMENT_SUBSTRING ||
2556 // tag == REPLACEMENT_STRING: data is index into array of substrings
2557 // of the replacement string.
2558 // tag <= 0: Temporary representation of the substring of the replacement
2559 // string ranging over -tag .. data.
2560 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2561 // substring objects.
2562 int data;
2563 };
2564
2565 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002566 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002567 Vector<Char> characters,
2568 int capture_count,
2569 int subject_length) {
2570 int length = characters.length();
2571 int last = 0;
2572 for (int i = 0; i < length; i++) {
2573 Char c = characters[i];
2574 if (c == '$') {
2575 int next_index = i + 1;
2576 if (next_index == length) { // No next character!
2577 break;
2578 }
2579 Char c2 = characters[next_index];
2580 switch (c2) {
2581 case '$':
2582 if (i > last) {
2583 // There is a substring before. Include the first "$".
2584 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2585 last = next_index + 1; // Continue after the second "$".
2586 } else {
2587 // Let the next substring start with the second "$".
2588 last = next_index;
2589 }
2590 i = next_index;
2591 break;
2592 case '`':
2593 if (i > last) {
2594 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2595 }
2596 parts->Add(ReplacementPart::SubjectPrefix());
2597 i = next_index;
2598 last = i + 1;
2599 break;
2600 case '\'':
2601 if (i > last) {
2602 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2603 }
2604 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2605 i = next_index;
2606 last = i + 1;
2607 break;
2608 case '&':
2609 if (i > last) {
2610 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2611 }
2612 parts->Add(ReplacementPart::SubjectMatch());
2613 i = next_index;
2614 last = i + 1;
2615 break;
2616 case '0':
2617 case '1':
2618 case '2':
2619 case '3':
2620 case '4':
2621 case '5':
2622 case '6':
2623 case '7':
2624 case '8':
2625 case '9': {
2626 int capture_ref = c2 - '0';
2627 if (capture_ref > capture_count) {
2628 i = next_index;
2629 continue;
2630 }
2631 int second_digit_index = next_index + 1;
2632 if (second_digit_index < length) {
2633 // Peek ahead to see if we have two digits.
2634 Char c3 = characters[second_digit_index];
2635 if ('0' <= c3 && c3 <= '9') { // Double digits.
2636 int double_digit_ref = capture_ref * 10 + c3 - '0';
2637 if (double_digit_ref <= capture_count) {
2638 next_index = second_digit_index;
2639 capture_ref = double_digit_ref;
2640 }
2641 }
2642 }
2643 if (capture_ref > 0) {
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002647 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002648 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2649 last = next_index + 1;
2650 }
2651 i = next_index;
2652 break;
2653 }
2654 default:
2655 i = next_index;
2656 break;
2657 }
2658 }
2659 }
2660 if (length > last) {
2661 if (last == 0) {
2662 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002663 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002664 } else {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2666 }
2667 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669 }
2670
2671 ZoneList<ReplacementPart> parts_;
2672 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002673 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674};
2675
2676
2677void CompiledReplacement::Compile(Handle<String> replacement,
2678 int capture_count,
2679 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002680 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002682 String::FlatContent content = replacement->GetFlatContent();
2683 ASSERT(content.IsFlat());
2684 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002685 simple_hint_ = ParseReplacementPattern(&parts_,
2686 content.ToAsciiVector(),
2687 capture_count,
2688 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002689 } else {
2690 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002691 simple_hint_ = ParseReplacementPattern(&parts_,
2692 content.ToUC16Vector(),
2693 capture_count,
2694 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002697 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002698 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 int substring_index = 0;
2700 for (int i = 0, n = parts_.length(); i < n; i++) {
2701 int tag = parts_[i].tag;
2702 if (tag <= 0) { // A replacement string slice.
2703 int from = -tag;
2704 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002705 replacement_substrings_.Add(
2706 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 parts_[i].tag = REPLACEMENT_SUBSTRING;
2708 parts_[i].data = substring_index;
2709 substring_index++;
2710 } else if (tag == REPLACEMENT_STRING) {
2711 replacement_substrings_.Add(replacement);
2712 parts_[i].data = substring_index;
2713 substring_index++;
2714 }
2715 }
2716}
2717
2718
2719void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2720 int match_from,
2721 int match_to,
2722 Handle<JSArray> last_match_info) {
2723 for (int i = 0, n = parts_.length(); i < n; i++) {
2724 ReplacementPart part = parts_[i];
2725 switch (part.tag) {
2726 case SUBJECT_PREFIX:
2727 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2728 break;
2729 case SUBJECT_SUFFIX: {
2730 int subject_length = part.data;
2731 if (match_to < subject_length) {
2732 builder->AddSubjectSlice(match_to, subject_length);
2733 }
2734 break;
2735 }
2736 case SUBJECT_CAPTURE: {
2737 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002738 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002739 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2740 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2741 if (from >= 0 && to > from) {
2742 builder->AddSubjectSlice(from, to);
2743 }
2744 break;
2745 }
2746 case REPLACEMENT_SUBSTRING:
2747 case REPLACEMENT_STRING:
2748 builder->AddString(replacement_substrings_[part.data]);
2749 break;
2750 default:
2751 UNREACHABLE();
2752 }
2753 }
2754}
2755
2756
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002757void FindAsciiStringIndices(Vector<const char> subject,
2758 char pattern,
2759 ZoneList<int>* indices,
2760 unsigned int limit) {
2761 ASSERT(limit > 0);
2762 // Collect indices of pattern in subject using memchr.
2763 // Stop after finding at most limit values.
2764 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2765 const char* subject_end = subject_start + subject.length();
2766 const char* pos = subject_start;
2767 while (limit > 0) {
2768 pos = reinterpret_cast<const char*>(
2769 memchr(pos, pattern, subject_end - pos));
2770 if (pos == NULL) return;
2771 indices->Add(static_cast<int>(pos - subject_start));
2772 pos++;
2773 limit--;
2774 }
2775}
2776
2777
2778template <typename SubjectChar, typename PatternChar>
2779void FindStringIndices(Isolate* isolate,
2780 Vector<const SubjectChar> subject,
2781 Vector<const PatternChar> pattern,
2782 ZoneList<int>* indices,
2783 unsigned int limit) {
2784 ASSERT(limit > 0);
2785 // Collect indices of pattern in subject.
2786 // Stop after finding at most limit values.
2787 int pattern_length = pattern.length();
2788 int index = 0;
2789 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2790 while (limit > 0) {
2791 index = search.Search(subject, index);
2792 if (index < 0) return;
2793 indices->Add(index);
2794 index += pattern_length;
2795 limit--;
2796 }
2797}
2798
2799
2800void FindStringIndicesDispatch(Isolate* isolate,
2801 String* subject,
2802 String* pattern,
2803 ZoneList<int>* indices,
2804 unsigned int limit) {
2805 {
2806 AssertNoAllocation no_gc;
2807 String::FlatContent subject_content = subject->GetFlatContent();
2808 String::FlatContent pattern_content = pattern->GetFlatContent();
2809 ASSERT(subject_content.IsFlat());
2810 ASSERT(pattern_content.IsFlat());
2811 if (subject_content.IsAscii()) {
2812 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2813 if (pattern_content.IsAscii()) {
2814 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2815 if (pattern_vector.length() == 1) {
2816 FindAsciiStringIndices(subject_vector,
2817 pattern_vector[0],
2818 indices,
2819 limit);
2820 } else {
2821 FindStringIndices(isolate,
2822 subject_vector,
2823 pattern_vector,
2824 indices,
2825 limit);
2826 }
2827 } else {
2828 FindStringIndices(isolate,
2829 subject_vector,
2830 pattern_content.ToUC16Vector(),
2831 indices,
2832 limit);
2833 }
2834 } else {
2835 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002836 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002837 FindStringIndices(isolate,
2838 subject_vector,
2839 pattern_content.ToAsciiVector(),
2840 indices,
2841 limit);
2842 } else {
2843 FindStringIndices(isolate,
2844 subject_vector,
2845 pattern_content.ToUC16Vector(),
2846 indices,
2847 limit);
2848 }
2849 }
2850 }
2851}
2852
2853
2854template<typename ResultSeqString>
2855MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2856 Isolate* isolate,
2857 Handle<String> subject,
2858 Handle<JSRegExp> pattern_regexp,
2859 Handle<String> replacement) {
2860 ASSERT(subject->IsFlat());
2861 ASSERT(replacement->IsFlat());
2862
2863 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2864 ZoneList<int> indices(8);
2865 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2866 String* pattern =
2867 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2868 int subject_len = subject->length();
2869 int pattern_len = pattern->length();
2870 int replacement_len = replacement->length();
2871
2872 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2873
2874 int matches = indices.length();
2875 if (matches == 0) return *subject;
2876
2877 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2878 int subject_pos = 0;
2879 int result_pos = 0;
2880
2881 Handle<ResultSeqString> result;
2882 if (ResultSeqString::kHasAsciiEncoding) {
2883 result = Handle<ResultSeqString>::cast(
2884 isolate->factory()->NewRawAsciiString(result_len));
2885 } else {
2886 result = Handle<ResultSeqString>::cast(
2887 isolate->factory()->NewRawTwoByteString(result_len));
2888 }
2889
2890 for (int i = 0; i < matches; i++) {
2891 // Copy non-matched subject content.
2892 if (subject_pos < indices.at(i)) {
2893 String::WriteToFlat(*subject,
2894 result->GetChars() + result_pos,
2895 subject_pos,
2896 indices.at(i));
2897 result_pos += indices.at(i) - subject_pos;
2898 }
2899
2900 // Replace match.
2901 if (replacement_len > 0) {
2902 String::WriteToFlat(*replacement,
2903 result->GetChars() + result_pos,
2904 0,
2905 replacement_len);
2906 result_pos += replacement_len;
2907 }
2908
2909 subject_pos = indices.at(i) + pattern_len;
2910 }
2911 // Add remaining subject content at the end.
2912 if (subject_pos < subject_len) {
2913 String::WriteToFlat(*subject,
2914 result->GetChars() + result_pos,
2915 subject_pos,
2916 subject_len);
2917 }
2918 return *result;
2919}
2920
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002921
lrn@chromium.org303ada72010-10-27 09:33:13 +00002922MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002924 String* subject,
2925 JSRegExp* regexp,
2926 String* replacement,
2927 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002928 ASSERT(subject->IsFlat());
2929 ASSERT(replacement->IsFlat());
2930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002931 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002932
2933 int length = subject->length();
2934 Handle<String> subject_handle(subject);
2935 Handle<JSRegExp> regexp_handle(regexp);
2936 Handle<String> replacement_handle(replacement);
2937 Handle<JSArray> last_match_info_handle(last_match_info);
2938 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2939 subject_handle,
2940 0,
2941 last_match_info_handle);
2942 if (match.is_null()) {
2943 return Failure::Exception();
2944 }
2945 if (match->IsNull()) {
2946 return *subject_handle;
2947 }
2948
2949 int capture_count = regexp_handle->CaptureCount();
2950
2951 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002952 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002953 CompiledReplacement compiled_replacement;
2954 compiled_replacement.Compile(replacement_handle,
2955 capture_count,
2956 length);
2957
2958 bool is_global = regexp_handle->GetFlags().is_global();
2959
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002960 // Shortcut for simple non-regexp global replacements
2961 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002962 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002963 compiled_replacement.simple_hint()) {
2964 if (subject_handle->HasOnlyAsciiChars() &&
2965 replacement_handle->HasOnlyAsciiChars()) {
2966 return StringReplaceStringWithString<SeqAsciiString>(
2967 isolate, subject_handle, regexp_handle, replacement_handle);
2968 } else {
2969 return StringReplaceStringWithString<SeqTwoByteString>(
2970 isolate, subject_handle, regexp_handle, replacement_handle);
2971 }
2972 }
2973
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002974 // Guessing the number of parts that the final result string is built
2975 // from. Global regexps can match any number of times, so we guess
2976 // conservatively.
2977 int expected_parts =
2978 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002979 ReplacementStringBuilder builder(isolate->heap(),
2980 subject_handle,
2981 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002982
2983 // Index of end of last match.
2984 int prev = 0;
2985
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002986 // Number of parts added by compiled replacement plus preceeding
2987 // string and possibly suffix after last match. It is possible for
2988 // all components to use two elements when encoded as two smis.
2989 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002990 bool matched = true;
2991 do {
2992 ASSERT(last_match_info_handle->HasFastElements());
2993 // Increase the capacity of the builder before entering local handle-scope,
2994 // so its internal buffer can safely allocate a new handle if it grows.
2995 builder.EnsureCapacity(parts_added_per_loop);
2996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002997 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002998 int start, end;
2999 {
3000 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003001 FixedArray* match_info_array =
3002 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003003
3004 ASSERT_EQ(capture_count * 2 + 2,
3005 RegExpImpl::GetLastCaptureCount(match_info_array));
3006 start = RegExpImpl::GetCapture(match_info_array, 0);
3007 end = RegExpImpl::GetCapture(match_info_array, 1);
3008 }
3009
3010 if (prev < start) {
3011 builder.AddSubjectSlice(prev, start);
3012 }
3013 compiled_replacement.Apply(&builder,
3014 start,
3015 end,
3016 last_match_info_handle);
3017 prev = end;
3018
3019 // Only continue checking for global regexps.
3020 if (!is_global) break;
3021
3022 // Continue from where the match ended, unless it was an empty match.
3023 int next = end;
3024 if (start == end) {
3025 next = end + 1;
3026 if (next > length) break;
3027 }
3028
3029 match = RegExpImpl::Exec(regexp_handle,
3030 subject_handle,
3031 next,
3032 last_match_info_handle);
3033 if (match.is_null()) {
3034 return Failure::Exception();
3035 }
3036 matched = !match->IsNull();
3037 } while (matched);
3038
3039 if (prev < length) {
3040 builder.AddSubjectSlice(prev, length);
3041 }
3042
3043 return *(builder.ToString());
3044}
3045
3046
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003047template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003048MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003049 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003050 String* subject,
3051 JSRegExp* regexp,
3052 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003053 ASSERT(subject->IsFlat());
3054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003056
3057 Handle<String> subject_handle(subject);
3058 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003059
3060 // Shortcut for simple non-regexp global replacements
3061 if (regexp_handle->GetFlags().is_global() &&
3062 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3063 Handle<String> empty_string_handle(HEAP->empty_string());
3064 if (subject_handle->HasOnlyAsciiChars()) {
3065 return StringReplaceStringWithString<SeqAsciiString>(
3066 isolate, subject_handle, regexp_handle, empty_string_handle);
3067 } else {
3068 return StringReplaceStringWithString<SeqTwoByteString>(
3069 isolate, subject_handle, regexp_handle, empty_string_handle);
3070 }
3071 }
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073 Handle<JSArray> last_match_info_handle(last_match_info);
3074 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3075 subject_handle,
3076 0,
3077 last_match_info_handle);
3078 if (match.is_null()) return Failure::Exception();
3079 if (match->IsNull()) return *subject_handle;
3080
3081 ASSERT(last_match_info_handle->HasFastElements());
3082
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003083 int start, end;
3084 {
3085 AssertNoAllocation match_info_array_is_not_in_a_handle;
3086 FixedArray* match_info_array =
3087 FixedArray::cast(last_match_info_handle->elements());
3088
3089 start = RegExpImpl::GetCapture(match_info_array, 0);
3090 end = RegExpImpl::GetCapture(match_info_array, 1);
3091 }
3092
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003093 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003094 int new_length = length - (end - start);
3095 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003097 }
3098 Handle<ResultSeqString> answer;
3099 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003100 answer = Handle<ResultSeqString>::cast(
3101 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003103 answer = Handle<ResultSeqString>::cast(
3104 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003105 }
3106
3107 // If the regexp isn't global, only match once.
3108 if (!regexp_handle->GetFlags().is_global()) {
3109 if (start > 0) {
3110 String::WriteToFlat(*subject_handle,
3111 answer->GetChars(),
3112 0,
3113 start);
3114 }
3115 if (end < length) {
3116 String::WriteToFlat(*subject_handle,
3117 answer->GetChars() + start,
3118 end,
3119 length);
3120 }
3121 return *answer;
3122 }
3123
3124 int prev = 0; // Index of end of last match.
3125 int next = 0; // Start of next search (prev unless last match was empty).
3126 int position = 0;
3127
3128 do {
3129 if (prev < start) {
3130 // Add substring subject[prev;start] to answer string.
3131 String::WriteToFlat(*subject_handle,
3132 answer->GetChars() + position,
3133 prev,
3134 start);
3135 position += start - prev;
3136 }
3137 prev = end;
3138 next = end;
3139 // Continue from where the match ended, unless it was an empty match.
3140 if (start == end) {
3141 next++;
3142 if (next > length) break;
3143 }
3144 match = RegExpImpl::Exec(regexp_handle,
3145 subject_handle,
3146 next,
3147 last_match_info_handle);
3148 if (match.is_null()) return Failure::Exception();
3149 if (match->IsNull()) break;
3150
3151 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003153 {
3154 AssertNoAllocation match_info_array_is_not_in_a_handle;
3155 FixedArray* match_info_array =
3156 FixedArray::cast(last_match_info_handle->elements());
3157 start = RegExpImpl::GetCapture(match_info_array, 0);
3158 end = RegExpImpl::GetCapture(match_info_array, 1);
3159 }
3160 } while (true);
3161
3162 if (prev < length) {
3163 // Add substring subject[prev;length] to answer string.
3164 String::WriteToFlat(*subject_handle,
3165 answer->GetChars() + position,
3166 prev,
3167 length);
3168 position += length - prev;
3169 }
3170
3171 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003173 }
3174
3175 // Shorten string and fill
3176 int string_size = ResultSeqString::SizeFor(position);
3177 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3178 int delta = allocated_string_size - string_size;
3179
3180 answer->set_length(position);
3181 if (delta == 0) return *answer;
3182
3183 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003185 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3186 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3187 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188
3189 return *answer;
3190}
3191
3192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003193RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003194 ASSERT(args.length() == 4);
3195
3196 CONVERT_CHECKED(String, subject, args[0]);
3197 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003198 Object* flat_subject;
3199 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3200 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3201 return maybe_flat_subject;
3202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003203 }
3204 subject = String::cast(flat_subject);
3205 }
3206
3207 CONVERT_CHECKED(String, replacement, args[2]);
3208 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003209 Object* flat_replacement;
3210 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3211 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3212 return maybe_flat_replacement;
3213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003214 }
3215 replacement = String::cast(flat_replacement);
3216 }
3217
3218 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3219 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3220
3221 ASSERT(last_match_info->HasFastElements());
3222
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223 if (replacement->length() == 0) {
3224 if (subject->HasOnlyAsciiChars()) {
3225 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003226 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003227 } else {
3228 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003230 }
3231 }
3232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003233 return StringReplaceRegExpWithString(isolate,
3234 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003235 regexp,
3236 replacement,
3237 last_match_info);
3238}
3239
3240
ager@chromium.org7c537e22008-10-16 08:43:32 +00003241// Perform string match of pattern on subject, starting at start index.
3242// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003243// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244int Runtime::StringMatch(Isolate* isolate,
3245 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003246 Handle<String> pat,
3247 int start_index) {
3248 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003250
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003251 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003252 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003254 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003255 if (start_index + pattern_length > subject_length) return -1;
3256
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003257 if (!sub->IsFlat()) FlattenString(sub);
3258 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003261 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003262 String::FlatContent seq_sub = sub->GetFlatContent();
3263 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003264
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003266 if (seq_pat.IsAscii()) {
3267 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3268 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003270 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003271 pat_vector,
3272 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003273 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003274 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003275 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003276 pat_vector,
3277 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003278 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003279 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3280 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003282 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 pat_vector,
3284 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003285 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003287 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 pat_vector,
3289 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003290}
3291
3292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003293RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003294 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003295 ASSERT(args.length() == 3);
3296
ager@chromium.org7c537e22008-10-16 08:43:32 +00003297 CONVERT_ARG_CHECKED(String, sub, 0);
3298 CONVERT_ARG_CHECKED(String, pat, 1);
3299
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003300 Object* index = args[2];
3301 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003302 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003303
ager@chromium.org870a0b62008-11-04 11:43:05 +00003304 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003305 int position =
3306 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003307 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308}
3309
3310
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003311template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003312static int StringMatchBackwards(Vector<const schar> subject,
3313 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003314 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003315 int pattern_length = pattern.length();
3316 ASSERT(pattern_length >= 1);
3317 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003318
3319 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003320 for (int i = 0; i < pattern_length; i++) {
3321 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003322 if (c > String::kMaxAsciiCharCode) {
3323 return -1;
3324 }
3325 }
3326 }
3327
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003328 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003329 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003330 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003331 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003332 while (j < pattern_length) {
3333 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003334 break;
3335 }
3336 j++;
3337 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003338 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003339 return i;
3340 }
3341 }
3342 return -1;
3343}
3344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003345RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 ASSERT(args.length() == 3);
3348
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003349 CONVERT_ARG_CHECKED(String, sub, 0);
3350 CONVERT_ARG_CHECKED(String, pat, 1);
3351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003354 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003355
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003356 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003359 if (start_index + pat_length > sub_length) {
3360 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003363 if (pat_length == 0) {
3364 return Smi::FromInt(start_index);
3365 }
3366
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003367 if (!sub->IsFlat()) FlattenString(sub);
3368 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3372
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 String::FlatContent sub_content = sub->GetFlatContent();
3374 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003376 if (pat_content.IsAscii()) {
3377 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3378 if (sub_content.IsAscii()) {
3379 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003380 pat_vector,
3381 start_index);
3382 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384 pat_vector,
3385 start_index);
3386 }
3387 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003388 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3389 if (sub_content.IsAscii()) {
3390 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003391 pat_vector,
3392 start_index);
3393 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003394 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003395 pat_vector,
3396 start_index);
3397 }
3398 }
3399
3400 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401}
3402
3403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003404RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 NoHandleAllocation ha;
3406 ASSERT(args.length() == 2);
3407
3408 CONVERT_CHECKED(String, str1, args[0]);
3409 CONVERT_CHECKED(String, str2, args[1]);
3410
3411 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 int str1_length = str1->length();
3413 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414
3415 // Decide trivial cases without flattening.
3416 if (str1_length == 0) {
3417 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3418 return Smi::FromInt(-str2_length);
3419 } else {
3420 if (str2_length == 0) return Smi::FromInt(str1_length);
3421 }
3422
3423 int end = str1_length < str2_length ? str1_length : str2_length;
3424
3425 // No need to flatten if we are going to find the answer on the first
3426 // character. At this point we know there is at least one character
3427 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003428 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 if (d != 0) return Smi::FromInt(d);
3430
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003431 str1->TryFlatten();
3432 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 StringInputBuffer& buf1 =
3435 *isolate->runtime_state()->string_locale_compare_buf1();
3436 StringInputBuffer& buf2 =
3437 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438
3439 buf1.Reset(str1);
3440 buf2.Reset(str2);
3441
3442 for (int i = 0; i < end; i++) {
3443 uint16_t char1 = buf1.GetNext();
3444 uint16_t char2 = buf2.GetNext();
3445 if (char1 != char2) return Smi::FromInt(char1 - char2);
3446 }
3447
3448 return Smi::FromInt(str1_length - str2_length);
3449}
3450
3451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003452RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453 NoHandleAllocation ha;
3454 ASSERT(args.length() == 3);
3455
3456 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003457 int start, end;
3458 // We have a fast integer-only case here to avoid a conversion to double in
3459 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003460 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3461 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3462 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3463 start = from_number;
3464 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003465 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003466 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3467 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003468 start = FastD2I(from_number);
3469 end = FastD2I(to_number);
3470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 RUNTIME_ASSERT(end >= start);
3472 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003473 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003474 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003475 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476}
3477
3478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003479RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003480 ASSERT_EQ(3, args.length());
3481
3482 CONVERT_ARG_CHECKED(String, subject, 0);
3483 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3484 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3485 HandleScope handles;
3486
3487 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3488
3489 if (match.is_null()) {
3490 return Failure::Exception();
3491 }
3492 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003493 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003494 }
3495 int length = subject->length();
3496
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003497 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003498 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003499 int start;
3500 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003501 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003502 {
3503 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003504 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003505 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3506 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3507 }
3508 offsets.Add(start);
3509 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003510 if (start == end) if (++end > length) break;
3511 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003512 if (match.is_null()) {
3513 return Failure::Exception();
3514 }
3515 } while (!match->IsNull());
3516 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003517 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003518 Handle<String> substring = isolate->factory()->
3519 NewSubString(subject, offsets.at(0), offsets.at(1));
3520 elements->set(0, *substring);
3521 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003522 int from = offsets.at(i * 2);
3523 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003524 Handle<String> substring = isolate->factory()->
3525 NewProperSubString(subject, from, to);
3526 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003529 result->set_length(Smi::FromInt(matches));
3530 return *result;
3531}
3532
3533
lrn@chromium.org25156de2010-04-06 13:10:27 +00003534// Two smis before and after the match, for very long strings.
3535const int kMaxBuilderEntriesPerRegExpMatch = 5;
3536
3537
3538static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3539 Handle<JSArray> last_match_info,
3540 int match_start,
3541 int match_end) {
3542 // Fill last_match_info with a single capture.
3543 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3544 AssertNoAllocation no_gc;
3545 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3546 RegExpImpl::SetLastCaptureCount(elements, 2);
3547 RegExpImpl::SetLastInput(elements, *subject);
3548 RegExpImpl::SetLastSubject(elements, *subject);
3549 RegExpImpl::SetCapture(elements, 0, match_start);
3550 RegExpImpl::SetCapture(elements, 1, match_end);
3551}
3552
3553
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003554template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003555static bool SearchStringMultiple(Isolate* isolate,
3556 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003557 Vector<const PatternChar> pattern,
3558 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 FixedArrayBuilder* builder,
3560 int* match_pos) {
3561 int pos = *match_pos;
3562 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003563 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003564 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003566 while (pos <= max_search_start) {
3567 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3568 *match_pos = pos;
3569 return false;
3570 }
3571 // Position of end of previous match.
3572 int match_end = pos + pattern_length;
3573 int new_pos = search.Search(subject, match_end);
3574 if (new_pos >= 0) {
3575 // A match.
3576 if (new_pos > match_end) {
3577 ReplacementStringBuilder::AddSubjectSlice(builder,
3578 match_end,
3579 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003580 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003581 pos = new_pos;
3582 builder->Add(pattern_string);
3583 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003584 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003585 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003586 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003587
lrn@chromium.org25156de2010-04-06 13:10:27 +00003588 if (pos < max_search_start) {
3589 ReplacementStringBuilder::AddSubjectSlice(builder,
3590 pos + pattern_length,
3591 subject_length);
3592 }
3593 *match_pos = pos;
3594 return true;
3595}
3596
3597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003598static bool SearchStringMultiple(Isolate* isolate,
3599 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003600 Handle<String> pattern,
3601 Handle<JSArray> last_match_info,
3602 FixedArrayBuilder* builder) {
3603 ASSERT(subject->IsFlat());
3604 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003605
3606 // Treating as if a previous match was before first character.
3607 int match_pos = -pattern->length();
3608
3609 for (;;) { // Break when search complete.
3610 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3611 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003612 String::FlatContent subject_content = subject->GetFlatContent();
3613 String::FlatContent pattern_content = pattern->GetFlatContent();
3614 if (subject_content.IsAscii()) {
3615 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3616 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 if (SearchStringMultiple(isolate,
3618 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003619 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003620 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003621 builder,
3622 &match_pos)) break;
3623 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 if (SearchStringMultiple(isolate,
3625 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003626 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003627 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003628 builder,
3629 &match_pos)) break;
3630 }
3631 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003632 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3633 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 if (SearchStringMultiple(isolate,
3635 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003636 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003637 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003638 builder,
3639 &match_pos)) break;
3640 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 if (SearchStringMultiple(isolate,
3642 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003643 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003645 builder,
3646 &match_pos)) break;
3647 }
3648 }
3649 }
3650
3651 if (match_pos >= 0) {
3652 SetLastMatchInfoNoCaptures(subject,
3653 last_match_info,
3654 match_pos,
3655 match_pos + pattern->length());
3656 return true;
3657 }
3658 return false; // No matches at all.
3659}
3660
3661
3662static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 Handle<String> subject,
3665 Handle<JSRegExp> regexp,
3666 Handle<JSArray> last_match_array,
3667 FixedArrayBuilder* builder) {
3668 ASSERT(subject->IsFlat());
3669 int match_start = -1;
3670 int match_end = 0;
3671 int pos = 0;
3672 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3673 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3674
3675 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003676 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003677 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003678 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679
3680 for (;;) { // Break on failure, return on exception.
3681 RegExpImpl::IrregexpResult result =
3682 RegExpImpl::IrregexpExecOnce(regexp,
3683 subject,
3684 pos,
3685 register_vector);
3686 if (result == RegExpImpl::RE_SUCCESS) {
3687 match_start = register_vector[0];
3688 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3689 if (match_end < match_start) {
3690 ReplacementStringBuilder::AddSubjectSlice(builder,
3691 match_end,
3692 match_start);
3693 }
3694 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003696 if (!first) {
3697 builder->Add(*isolate->factory()->NewProperSubString(subject,
3698 match_start,
3699 match_end));
3700 } else {
3701 builder->Add(*isolate->factory()->NewSubString(subject,
3702 match_start,
3703 match_end));
3704 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003705 if (match_start != match_end) {
3706 pos = match_end;
3707 } else {
3708 pos = match_end + 1;
3709 if (pos > subject_length) break;
3710 }
3711 } else if (result == RegExpImpl::RE_FAILURE) {
3712 break;
3713 } else {
3714 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3715 return result;
3716 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003717 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003718 }
3719
3720 if (match_start >= 0) {
3721 if (match_end < subject_length) {
3722 ReplacementStringBuilder::AddSubjectSlice(builder,
3723 match_end,
3724 subject_length);
3725 }
3726 SetLastMatchInfoNoCaptures(subject,
3727 last_match_array,
3728 match_start,
3729 match_end);
3730 return RegExpImpl::RE_SUCCESS;
3731 } else {
3732 return RegExpImpl::RE_FAILURE; // No matches at all.
3733 }
3734}
3735
3736
3737static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 Handle<String> subject,
3740 Handle<JSRegExp> regexp,
3741 Handle<JSArray> last_match_array,
3742 FixedArrayBuilder* builder) {
3743
3744 ASSERT(subject->IsFlat());
3745 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3746 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3747
3748 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003749 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003750
3751 RegExpImpl::IrregexpResult result =
3752 RegExpImpl::IrregexpExecOnce(regexp,
3753 subject,
3754 0,
3755 register_vector);
3756
3757 int capture_count = regexp->CaptureCount();
3758 int subject_length = subject->length();
3759
3760 // Position to search from.
3761 int pos = 0;
3762 // End of previous match. Differs from pos if match was empty.
3763 int match_end = 0;
3764 if (result == RegExpImpl::RE_SUCCESS) {
3765 // Need to keep a copy of the previous match for creating last_match_info
3766 // at the end, so we have two vectors that we swap between.
3767 OffsetsVector registers2(required_registers);
3768 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003769 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003770 do {
3771 int match_start = register_vector[0];
3772 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3773 if (match_end < match_start) {
3774 ReplacementStringBuilder::AddSubjectSlice(builder,
3775 match_end,
3776 match_start);
3777 }
3778 match_end = register_vector[1];
3779
3780 {
3781 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003782 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003783 // Arguments array to replace function is match, captures, index and
3784 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 Handle<FixedArray> elements =
3786 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003787 Handle<String> match;
3788 if (!first) {
3789 match = isolate->factory()->NewProperSubString(subject,
3790 match_start,
3791 match_end);
3792 } else {
3793 match = isolate->factory()->NewSubString(subject,
3794 match_start,
3795 match_end);
3796 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003797 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003798 for (int i = 1; i <= capture_count; i++) {
3799 int start = register_vector[i * 2];
3800 if (start >= 0) {
3801 int end = register_vector[i * 2 + 1];
3802 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003803 Handle<String> substring;
3804 if (!first) {
3805 substring = isolate->factory()->NewProperSubString(subject,
3806 start,
3807 end);
3808 } else {
3809 substring = isolate->factory()->NewSubString(subject, start, end);
3810 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003811 elements->set(i, *substring);
3812 } else {
3813 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003815 }
3816 }
3817 elements->set(capture_count + 1, Smi::FromInt(match_start));
3818 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003820 }
3821 // Swap register vectors, so the last successful match is in
3822 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003823 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003824 prev_register_vector = register_vector;
3825 register_vector = tmp;
3826
3827 if (match_end > match_start) {
3828 pos = match_end;
3829 } else {
3830 pos = match_end + 1;
3831 if (pos > subject_length) {
3832 break;
3833 }
3834 }
3835
3836 result = RegExpImpl::IrregexpExecOnce(regexp,
3837 subject,
3838 pos,
3839 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003840 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003841 } while (result == RegExpImpl::RE_SUCCESS);
3842
3843 if (result != RegExpImpl::RE_EXCEPTION) {
3844 // Finished matching, with at least one match.
3845 if (match_end < subject_length) {
3846 ReplacementStringBuilder::AddSubjectSlice(builder,
3847 match_end,
3848 subject_length);
3849 }
3850
3851 int last_match_capture_count = (capture_count + 1) * 2;
3852 int last_match_array_size =
3853 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3854 last_match_array->EnsureSize(last_match_array_size);
3855 AssertNoAllocation no_gc;
3856 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3857 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3858 RegExpImpl::SetLastSubject(elements, *subject);
3859 RegExpImpl::SetLastInput(elements, *subject);
3860 for (int i = 0; i < last_match_capture_count; i++) {
3861 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3862 }
3863 return RegExpImpl::RE_SUCCESS;
3864 }
3865 }
3866 // No matches at all, return failure or exception result directly.
3867 return result;
3868}
3869
3870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003871RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003874
3875 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003876 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003877 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3878 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3879 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3880
3881 ASSERT(last_match_info->HasFastElements());
3882 ASSERT(regexp->GetFlags().is_global());
3883 Handle<FixedArray> result_elements;
3884 if (result_array->HasFastElements()) {
3885 result_elements =
3886 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003887 }
3888 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003890 }
3891 FixedArrayBuilder builder(result_elements);
3892
3893 if (regexp->TypeTag() == JSRegExp::ATOM) {
3894 Handle<String> pattern(
3895 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003896 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 if (SearchStringMultiple(isolate, subject, pattern,
3898 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003899 return *builder.ToJSArray(result_array);
3900 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 }
3903
3904 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3905
3906 RegExpImpl::IrregexpResult result;
3907 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003908 result = SearchRegExpNoCaptureMultiple(isolate,
3909 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 regexp,
3911 last_match_info,
3912 &builder);
3913 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003914 result = SearchRegExpMultiple(isolate,
3915 subject,
3916 regexp,
3917 last_match_info,
3918 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003921 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003922 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3923 return Failure::Exception();
3924}
3925
3926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003927RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 NoHandleAllocation ha;
3929 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003930 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003931 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003933 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003934 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003935 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003936 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 // Character array used for conversion.
3938 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003939 return isolate->heap()->
3940 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003941 }
3942 }
3943
3944 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003945 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003947 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 }
3949 if (isinf(value)) {
3950 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003951 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003952 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003953 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003956 MaybeObject* result =
3957 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958 DeleteArray(str);
3959 return result;
3960}
3961
3962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003963RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964 NoHandleAllocation ha;
3965 ASSERT(args.length() == 2);
3966
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003967 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003969 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 }
3971 if (isinf(value)) {
3972 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003973 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003975 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003977 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 int f = FastD2I(f_number);
3979 RUNTIME_ASSERT(f >= 0);
3980 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 MaybeObject* res =
3982 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985}
3986
3987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003988RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 NoHandleAllocation ha;
3990 ASSERT(args.length() == 2);
3991
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003992 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003994 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 }
3996 if (isinf(value)) {
3997 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004000 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004002 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 int f = FastD2I(f_number);
4004 RUNTIME_ASSERT(f >= -1 && f <= 20);
4005 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 MaybeObject* res =
4007 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010}
4011
4012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004013RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 NoHandleAllocation ha;
4015 ASSERT(args.length() == 2);
4016
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004017 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
4021 if (isinf(value)) {
4022 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004023 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004025 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004027 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 int f = FastD2I(f_number);
4029 RUNTIME_ASSERT(f >= 1 && f <= 21);
4030 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004031 MaybeObject* res =
4032 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004034 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035}
4036
4037
4038// Returns a single character string where first character equals
4039// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004041 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004042 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004043 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004044 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004046 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047}
4048
4049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004050MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4051 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004052 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 // Handle [] indexing on Strings
4054 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004055 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4056 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 }
4058
4059 // Handle [] indexing on String objects
4060 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004061 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4062 Handle<Object> result =
4063 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4064 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 }
4066
4067 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004068 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 return prototype->GetElement(index);
4070 }
4071
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004072 return GetElement(object, index);
4073}
4074
4075
lrn@chromium.org303ada72010-10-27 09:33:13 +00004076MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 return object->GetElement(index);
4078}
4079
4080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4082 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004083 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004087 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 isolate->factory()->NewTypeError("non_object_property_load",
4090 HandleVector(args, 2));
4091 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
4093
4094 // Check if the given key is an array index.
4095 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004096 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004097 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
4099
4100 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 bool has_pending_exception = false;
4106 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004107 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004109 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 }
4111
ager@chromium.org32912102009-01-16 10:38:43 +00004112 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 // the element if so.
4114 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004115 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004117 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 }
4119}
4120
4121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004122RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 NoHandleAllocation ha;
4124 ASSERT(args.length() == 2);
4125
4126 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004127 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130}
4131
4132
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004133// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004134RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004135 NoHandleAllocation ha;
4136 ASSERT(args.length() == 2);
4137
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004138 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004139 // itself.
4140 //
4141 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004142 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004143 // global proxy object never has properties. This is the case
4144 // because the global proxy object forwards everything to its hidden
4145 // prototype including local lookups.
4146 //
4147 // Additionally, we need to make sure that we do not cache results
4148 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004149 if (args[0]->IsJSObject() &&
4150 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004151 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004152 args[1]->IsString()) {
4153 JSObject* receiver = JSObject::cast(args[0]);
4154 String* key = String::cast(args[1]);
4155 if (receiver->HasFastProperties()) {
4156 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004157 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4159 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004160 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004161 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004162 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004163 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004164 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004165 LookupResult result;
4166 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004167 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004168 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004170 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004171 }
4172 } else {
4173 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004174 StringDictionary* dictionary = receiver->property_dictionary();
4175 int entry = dictionary->FindEntry(key);
4176 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004177 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004178 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004179 if (!receiver->IsGlobalObject()) return value;
4180 value = JSGlobalPropertyCell::cast(value)->value();
4181 if (!value->IsTheHole()) return value;
4182 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004183 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004184 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004185 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4186 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004188 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004189 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004190 if (index >= 0 && index < str->length()) {
4191 Handle<Object> result = GetCharAt(str, index);
4192 return *result;
4193 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004194 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004195
4196 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004197 return Runtime::GetObjectProperty(isolate,
4198 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004199 args.at<Object>(1));
4200}
4201
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004202// Implements part of 8.12.9 DefineOwnProperty.
4203// There are 3 cases that lead here:
4204// Step 4b - define a new accessor property.
4205// Steps 9c & 12 - replace an existing data property with an accessor property.
4206// Step 12 - update an existing accessor property with an accessor or generic
4207// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004209 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004210 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004211 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4212 CONVERT_CHECKED(String, name, args[1]);
4213 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004214 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004215 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004216 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4217 int unchecked = flag_attr->value();
4218 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4219 RUNTIME_ASSERT(!obj->IsNull());
4220 LookupResult result;
4221 obj->LocalLookupRealNamedProperty(name, &result);
4222
4223 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4224 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4225 // delete it to avoid running into trouble in DefineAccessor, which
4226 // handles this incorrectly if the property is readonly (does nothing)
4227 if (result.IsProperty() &&
4228 (result.type() == FIELD || result.type() == NORMAL
4229 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004230 Object* ok;
4231 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004232 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004233 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4234 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004235 }
4236 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4237}
4238
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004239// Implements part of 8.12.9 DefineOwnProperty.
4240// There are 3 cases that lead here:
4241// Step 4a - define a new data property.
4242// Steps 9b & 12 - replace an existing accessor property with a data property.
4243// Step 12 - update an existing data property with a data or generic
4244// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004245RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004246 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004248 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4249 CONVERT_ARG_CHECKED(String, name, 1);
4250 Handle<Object> obj_value = args.at<Object>(2);
4251
4252 CONVERT_CHECKED(Smi, flag, args[3]);
4253 int unchecked = flag->value();
4254 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4255
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004256 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4257
4258 // Check if this is an element.
4259 uint32_t index;
4260 bool is_element = name->AsArrayIndex(&index);
4261
4262 // Special case for elements if any of the flags are true.
4263 // If elements are in fast case we always implicitly assume that:
4264 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4265 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4266 is_element) {
4267 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004268 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004269 // We do not need to do access checks here since these has already
4270 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004271 Handle<Object> proto(js_object->GetPrototype());
4272 // If proxy is detached, ignore the assignment. Alternatively,
4273 // we could throw an exception.
4274 if (proto->IsNull()) return *obj_value;
4275 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004276 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004277
4278 // Don't allow element properties to be redefined on objects with external
4279 // array elements.
4280 if (js_object->HasExternalArrayElements()) {
4281 Handle<Object> args[2] = { js_object, name };
4282 Handle<Object> error =
4283 isolate->factory()->NewTypeError("redef_external_array_element",
4284 HandleVector(args, 2));
4285 return isolate->Throw(*error);
4286 }
4287
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004288 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004289 // Make sure that we never go back to fast case.
4290 dictionary->set_requires_slow_elements();
4291 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004292 Handle<NumberDictionary> extended_dictionary =
4293 NumberDictionarySet(dictionary, index, obj_value, details);
4294 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004295 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004296 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4297 } else {
4298 js_object->set_elements(*extended_dictionary);
4299 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004300 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004301 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004302 }
4303
ager@chromium.org5c838252010-02-19 08:53:10 +00004304 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004305 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004306
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004307 // To be compatible with safari we do not change the value on API objects
4308 // in defineProperty. Firefox disagrees here, and actually changes the value.
4309 if (result.IsProperty() &&
4310 (result.type() == CALLBACKS) &&
4311 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004313 }
4314
ager@chromium.org5c838252010-02-19 08:53:10 +00004315 // Take special care when attributes are different and there is already
4316 // a property. For simplicity we normalize the property which enables us
4317 // to not worry about changing the instance_descriptor and creating a new
4318 // map. The current version of SetObjectProperty does not handle attributes
4319 // correctly in the case where a property is a field and is reset with
4320 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004321 if (result.IsProperty() &&
4322 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004323 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004324 if (js_object->IsJSGlobalProxy()) {
4325 // Since the result is a property, the prototype will exist so
4326 // we don't have to check for null.
4327 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004328 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004329 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004330 // Use IgnoreAttributes version since a readonly property may be
4331 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004332 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4333 *obj_value,
4334 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004335 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 return Runtime::ForceSetObjectProperty(isolate,
4338 js_object,
4339 name,
4340 obj_value,
4341 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004342}
4343
4344
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004345// Special case for elements if any of the flags are true.
4346// If elements are in fast case we always implicitly assume that:
4347// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4348static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4349 Handle<JSObject> js_object,
4350 uint32_t index,
4351 Handle<Object> value,
4352 PropertyAttributes attr) {
4353 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004354 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004355 // Make sure that we never go back to fast case.
4356 dictionary->set_requires_slow_elements();
4357 PropertyDetails details = PropertyDetails(attr, NORMAL);
4358 Handle<NumberDictionary> extended_dictionary =
4359 NumberDictionarySet(dictionary, index, value, details);
4360 if (*extended_dictionary != *dictionary) {
4361 js_object->set_elements(*extended_dictionary);
4362 }
4363 return *value;
4364}
4365
4366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4368 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004369 Handle<Object> key,
4370 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004371 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004372 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004375 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004376 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 isolate->factory()->NewTypeError("non_object_property_store",
4379 HandleVector(args, 2));
4380 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004381 }
4382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004383 if (object->IsJSProxy()) {
4384 bool has_pending_exception = false;
4385 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4386 if (has_pending_exception) return Failure::Exception();
4387 return JSProxy::cast(*object)->SetProperty(
4388 String::cast(*name), *value, attr, strict_mode);
4389 }
4390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391 // If the object isn't a JavaScript object, we ignore the store.
4392 if (!object->IsJSObject()) return *value;
4393
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004394 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4395
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 // Check if the given key is an array index.
4397 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004398 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4400 // of a string using [] notation. We need to support this too in
4401 // JavaScript.
4402 // In the case of a String object we just need to redirect the assignment to
4403 // the underlying string if the index is in range. Since the underlying
4404 // string does nothing with the assignment then we can ignore such
4405 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004406 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004410 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4411 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4412 }
4413
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004414 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004415 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 return *value;
4417 }
4418
4419 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004420 Handle<Object> result;
4421 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004422 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4423 return NormalizeObjectSetElement(isolate,
4424 js_object,
4425 index,
4426 value,
4427 attr);
4428 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004429 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004432 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004433 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004435 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 return *value;
4437 }
4438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 bool has_pending_exception = false;
4441 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4442 if (has_pending_exception) return Failure::Exception();
4443 Handle<String> name = Handle<String>::cast(converted);
4444
4445 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004446 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004448 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 }
4450}
4451
4452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004453MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4454 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004455 Handle<Object> key,
4456 Handle<Object> value,
4457 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004458 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004459
4460 // Check if the given key is an array index.
4461 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004462 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
4470 if (js_object->IsStringObjectWithCharacterAt(index)) {
4471 return *value;
4472 }
4473
whesse@chromium.org7b260152011-06-20 15:33:18 +00004474 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004475 }
4476
4477 if (key->IsString()) {
4478 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004479 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004480 } else {
4481 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004482 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004483 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4484 *value,
4485 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004486 }
4487 }
4488
4489 // Call-back into JavaScript to convert the key to a string.
4490 bool has_pending_exception = false;
4491 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4492 if (has_pending_exception) return Failure::Exception();
4493 Handle<String> name = Handle<String>::cast(converted);
4494
4495 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004496 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004497 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004498 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004499 }
4500}
4501
4502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004504 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004507
4508 // Check if the given key is an array index.
4509 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004510 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004511 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4512 // characters of a string using [] notation. In the case of a
4513 // String object we just need to redirect the deletion to the
4514 // underlying string if the index is in range. Since the
4515 // underlying string does nothing with the deletion, we can ignore
4516 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004517 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004518 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004519 }
4520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004521 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004522 }
4523
4524 Handle<String> key_string;
4525 if (key->IsString()) {
4526 key_string = Handle<String>::cast(key);
4527 } else {
4528 // Call-back into JavaScript to convert the key to a string.
4529 bool has_pending_exception = false;
4530 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4531 if (has_pending_exception) return Failure::Exception();
4532 key_string = Handle<String>::cast(converted);
4533 }
4534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004535 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004536 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004537}
4538
4539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004540RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004542 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543
4544 Handle<Object> object = args.at<Object>(0);
4545 Handle<Object> key = args.at<Object>(1);
4546 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004547 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004548 RUNTIME_ASSERT(
4549 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004551 PropertyAttributes attributes =
4552 static_cast<PropertyAttributes>(unchecked_attributes);
4553
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004554 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004555 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004556 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004557 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4558 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004559 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004562 return Runtime::SetObjectProperty(isolate,
4563 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004564 key,
4565 value,
4566 attributes,
4567 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568}
4569
4570
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004571// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004572// This is used to decide if we should transform null and undefined
4573// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004575 NoHandleAllocation ha;
4576 RUNTIME_ASSERT(args.length() == 1);
4577
4578 Handle<Object> object = args.at<Object>(0);
4579
4580 if (object->IsJSFunction()) {
4581 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004582 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004583 }
4584 return isolate->heap()->undefined_value();
4585}
4586
4587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588// Set a local property, even if it is READ_ONLY. If the property does not
4589// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004590RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004592 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 CONVERT_CHECKED(JSObject, object, args[0]);
4594 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004595 // Compute attributes.
4596 PropertyAttributes attributes = NONE;
4597 if (args.length() == 4) {
4598 CONVERT_CHECKED(Smi, value_obj, args[3]);
4599 int unchecked_value = value_obj->value();
4600 // Only attribute bits should be set.
4601 RUNTIME_ASSERT(
4602 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4603 attributes = static_cast<PropertyAttributes>(unchecked_value);
4604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004606 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004607 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608}
4609
4610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004611RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004613 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004615 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004617 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004618 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004619 ? JSReceiver::STRICT_DELETION
4620 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621}
4622
4623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004624static Object* HasLocalPropertyImplementation(Isolate* isolate,
4625 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004626 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004628 // Handle hidden prototypes. If there's a hidden prototype above this thing
4629 // then we have to check it for properties, because they are supposed to
4630 // look like they are on this object.
4631 Handle<Object> proto(object->GetPrototype());
4632 if (proto->IsJSObject() &&
4633 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 return HasLocalPropertyImplementation(isolate,
4635 Handle<JSObject>::cast(proto),
4636 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004639}
4640
4641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004642RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 NoHandleAllocation ha;
4644 ASSERT(args.length() == 2);
4645 CONVERT_CHECKED(String, key, args[1]);
4646
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004647 uint32_t index;
4648 const bool key_is_array_index = key->AsArrayIndex(&index);
4649
ager@chromium.org9085a012009-05-11 19:22:57 +00004650 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004652 if (obj->IsJSObject()) {
4653 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004654 // Fast case: either the key is a real named property or it is not
4655 // an array index and there are no interceptors or hidden
4656 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004658 Map* map = object->map();
4659 if (!key_is_array_index &&
4660 !map->has_named_interceptor() &&
4661 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4662 return isolate->heap()->false_value();
4663 }
4664 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004665 HandleScope scope(isolate);
4666 return HasLocalPropertyImplementation(isolate,
4667 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004668 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004669 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004671 String* string = String::cast(obj);
4672 if (index < static_cast<uint32_t>(string->length())) {
4673 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 }
4675 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677}
4678
4679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004680RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 NoHandleAllocation na;
4682 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004683 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4684 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004686 bool result = receiver->HasProperty(key);
4687 if (isolate->has_pending_exception()) return Failure::Exception();
4688 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689}
4690
4691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 NoHandleAllocation na;
4694 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004695 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4696 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004698 bool result = receiver->HasElement(index->value());
4699 if (isolate->has_pending_exception()) return Failure::Exception();
4700 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701}
4702
4703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004704RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 NoHandleAllocation ha;
4706 ASSERT(args.length() == 2);
4707
4708 CONVERT_CHECKED(JSObject, object, args[0]);
4709 CONVERT_CHECKED(String, key, args[1]);
4710
4711 uint32_t index;
4712 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004713 JSObject::LocalElementType type = object->HasLocalElement(index);
4714 switch (type) {
4715 case JSObject::UNDEFINED_ELEMENT:
4716 case JSObject::STRING_CHARACTER_ELEMENT:
4717 return isolate->heap()->false_value();
4718 case JSObject::INTERCEPTED_ELEMENT:
4719 case JSObject::FAST_ELEMENT:
4720 return isolate->heap()->true_value();
4721 case JSObject::DICTIONARY_ELEMENT: {
4722 if (object->IsJSGlobalProxy()) {
4723 Object* proto = object->GetPrototype();
4724 if (proto->IsNull()) {
4725 return isolate->heap()->false_value();
4726 }
4727 ASSERT(proto->IsJSGlobalObject());
4728 object = JSObject::cast(proto);
4729 }
4730 FixedArray* elements = FixedArray::cast(object->elements());
4731 NumberDictionary* dictionary = NULL;
4732 if (elements->map() ==
4733 isolate->heap()->non_strict_arguments_elements_map()) {
4734 dictionary = NumberDictionary::cast(elements->get(1));
4735 } else {
4736 dictionary = NumberDictionary::cast(elements);
4737 }
4738 int entry = dictionary->FindEntry(index);
4739 ASSERT(entry != NumberDictionary::kNotFound);
4740 PropertyDetails details = dictionary->DetailsAt(entry);
4741 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4742 }
4743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 }
4745
ager@chromium.org870a0b62008-11-04 11:43:05 +00004746 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748}
4749
4750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004754 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 return *GetKeysFor(object);
4756}
4757
4758
4759// Returns either a FixedArray as Runtime_GetPropertyNames,
4760// or, if the given object has an enum cache that contains
4761// all enumerable properties of the object and its prototypes
4762// have none, the map of the object. This is used to speed up
4763// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 ASSERT(args.length() == 1);
4766
4767 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4768
4769 if (raw_object->IsSimpleEnum()) return raw_object->map();
4770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004771 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004773 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4774 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 // Test again, since cache may have been built by preceding call.
4777 if (object->IsSimpleEnum()) return object->map();
4778
4779 return *content;
4780}
4781
4782
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004783// Find the length of the prototype chain that is to to handled as one. If a
4784// prototype object is hidden it is to be viewed as part of the the object it
4785// is prototype for.
4786static int LocalPrototypeChainLength(JSObject* obj) {
4787 int count = 1;
4788 Object* proto = obj->GetPrototype();
4789 while (proto->IsJSObject() &&
4790 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4791 count++;
4792 proto = JSObject::cast(proto)->GetPrototype();
4793 }
4794 return count;
4795}
4796
4797
4798// Return the names of the local named properties.
4799// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004801 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004802 ASSERT(args.length() == 1);
4803 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004805 }
4806 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4807
4808 // Skip the global proxy as it has no properties and always delegates to the
4809 // real global object.
4810 if (obj->IsJSGlobalProxy()) {
4811 // Only collect names if access is permitted.
4812 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004813 !isolate->MayNamedAccess(*obj,
4814 isolate->heap()->undefined_value(),
4815 v8::ACCESS_KEYS)) {
4816 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4817 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004818 }
4819 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4820 }
4821
4822 // Find the number of objects making up this.
4823 int length = LocalPrototypeChainLength(*obj);
4824
4825 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004826 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004827 int total_property_count = 0;
4828 Handle<JSObject> jsproto = obj;
4829 for (int i = 0; i < length; i++) {
4830 // Only collect names if access is permitted.
4831 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 !isolate->MayNamedAccess(*jsproto,
4833 isolate->heap()->undefined_value(),
4834 v8::ACCESS_KEYS)) {
4835 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4836 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004837 }
4838 int n;
4839 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4840 local_property_count[i] = n;
4841 total_property_count += n;
4842 if (i < length - 1) {
4843 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4844 }
4845 }
4846
4847 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 Handle<FixedArray> names =
4849 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004850
4851 // Get the property names.
4852 jsproto = obj;
4853 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004854 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004855 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004856 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4857 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004858 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004859 proto_with_hidden_properties++;
4860 }
4861 if (i < length - 1) {
4862 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4863 }
4864 }
4865
4866 // Filter out name of hidden propeties object.
4867 if (proto_with_hidden_properties > 0) {
4868 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004870 names->length() - proto_with_hidden_properties);
4871 int dest_pos = 0;
4872 for (int i = 0; i < total_property_count; i++) {
4873 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004874 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004875 continue;
4876 }
4877 names->set(dest_pos++, name);
4878 }
4879 }
4880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004881 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004882}
4883
4884
4885// Return the names of the local indexed properties.
4886// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004888 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004889 ASSERT(args.length() == 1);
4890 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004892 }
4893 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4894
4895 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004896 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004897 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004898 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004899}
4900
4901
4902// Return information on whether an object has a named or indexed interceptor.
4903// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004905 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 ASSERT(args.length() == 1);
4907 if (!args[0]->IsJSObject()) {
4908 return Smi::FromInt(0);
4909 }
4910 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4911
4912 int result = 0;
4913 if (obj->HasNamedInterceptor()) result |= 2;
4914 if (obj->HasIndexedInterceptor()) result |= 1;
4915
4916 return Smi::FromInt(result);
4917}
4918
4919
4920// Return property names from named interceptor.
4921// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924 ASSERT(args.length() == 1);
4925 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4926
4927 if (obj->HasNamedInterceptor()) {
4928 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4929 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4930 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004932}
4933
4934
4935// Return element names from indexed interceptor.
4936// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004937RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004938 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004939 ASSERT(args.length() == 1);
4940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4941
4942 if (obj->HasIndexedInterceptor()) {
4943 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4944 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004947}
4948
4949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004950RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004951 ASSERT_EQ(args.length(), 1);
4952 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004953 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004954 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004955
4956 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004957 // Do access checks before going to the global object.
4958 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004959 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004960 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004961 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4962 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004963 }
4964
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004965 Handle<Object> proto(object->GetPrototype());
4966 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004968 object = Handle<JSObject>::cast(proto);
4969 }
4970
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004971 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4972 LOCAL_ONLY);
4973 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4974 // property array and since the result is mutable we have to create
4975 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004976 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004978 for (int i = 0; i < length; i++) {
4979 Object* entry = contents->get(i);
4980 if (entry->IsString()) {
4981 copy->set(i, entry);
4982 } else {
4983 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 HandleScope scope(isolate);
4985 Handle<Object> entry_handle(entry, isolate);
4986 Handle<Object> entry_str =
4987 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004988 copy->set(i, *entry_str);
4989 }
4990 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004992}
4993
4994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004996 NoHandleAllocation ha;
4997 ASSERT(args.length() == 1);
4998
4999 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005000 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 it.AdvanceToArgumentsFrame();
5002 JavaScriptFrame* frame = it.frame();
5003
5004 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005005 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006
5007 // Try to convert the key to an index. If successful and within
5008 // index return the the argument from the frame.
5009 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005010 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 return frame->GetParameter(index);
5012 }
5013
5014 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 bool exception = false;
5017 Handle<Object> converted =
5018 Execution::ToString(args.at<Object>(0), &exception);
5019 if (exception) return Failure::Exception();
5020 Handle<String> key = Handle<String>::cast(converted);
5021
5022 // Try to convert the string key into an array index.
5023 if (key->AsArrayIndex(&index)) {
5024 if (index < n) {
5025 return frame->GetParameter(index);
5026 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005028 }
5029 }
5030
5031 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5033 if (key->Equals(isolate->heap()->callee_symbol())) {
5034 Object* function = frame->function();
5035 if (function->IsJSFunction() &&
5036 JSFunction::cast(function)->shared()->strict_mode()) {
5037 return isolate->Throw(*isolate->factory()->NewTypeError(
5038 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5039 }
5040 return function;
5041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005042
5043 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005044 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005045}
5046
5047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005048RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005050
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005051 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005052 Handle<Object> object = args.at<Object>(0);
5053 if (object->IsJSObject()) {
5054 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005055 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005056 MaybeObject* ok = js_object->TransformToFastProperties(0);
5057 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005058 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005059 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005060 return *object;
5061}
5062
5063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005064RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005066
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005067 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005068 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005069 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005070 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005071 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005072 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005073 return *object;
5074}
5075
5076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 NoHandleAllocation ha;
5079 ASSERT(args.length() == 1);
5080
5081 return args[0]->ToBoolean();
5082}
5083
5084
5085// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5086// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005087RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088 NoHandleAllocation ha;
5089
5090 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 HeapObject* heap_obj = HeapObject::cast(obj);
5093
5094 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005095 if (heap_obj->map()->is_undetectable()) {
5096 return isolate->heap()->undefined_symbol();
5097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005098
5099 InstanceType instance_type = heap_obj->map()->instance_type();
5100 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102 }
5103
5104 switch (instance_type) {
5105 case ODDBALL_TYPE:
5106 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 }
5109 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005110 return FLAG_harmony_typeof
5111 ? isolate->heap()->null_symbol()
5112 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 }
5114 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005116 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005117 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 default:
5120 // For any kind of object not handled above, the spec rule for
5121 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123 }
5124}
5125
5126
lrn@chromium.org25156de2010-04-06 13:10:27 +00005127static bool AreDigits(const char*s, int from, int to) {
5128 for (int i = from; i < to; i++) {
5129 if (s[i] < '0' || s[i] > '9') return false;
5130 }
5131
5132 return true;
5133}
5134
5135
5136static int ParseDecimalInteger(const char*s, int from, int to) {
5137 ASSERT(to - from < 10); // Overflow is not possible.
5138 ASSERT(from < to);
5139 int d = s[from] - '0';
5140
5141 for (int i = from + 1; i < to; i++) {
5142 d = 10 * d + (s[i] - '0');
5143 }
5144
5145 return d;
5146}
5147
5148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005149RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005150 NoHandleAllocation ha;
5151 ASSERT(args.length() == 1);
5152 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005153 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005154
5155 // Fast case: short integer or some sorts of junk values.
5156 int len = subject->length();
5157 if (subject->IsSeqAsciiString()) {
5158 if (len == 0) return Smi::FromInt(0);
5159
5160 char const* data = SeqAsciiString::cast(subject)->GetChars();
5161 bool minus = (data[0] == '-');
5162 int start_pos = (minus ? 1 : 0);
5163
5164 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005166 } else if (data[start_pos] > '9') {
5167 // Fast check for a junk value. A valid string may start from a
5168 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5169 // the 'I' character ('Infinity'). All of that have codes not greater than
5170 // '9' except 'I'.
5171 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005173 }
5174 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5175 // The maximal/minimal smi has 10 digits. If the string has less digits we
5176 // know it will fit into the smi-data type.
5177 int d = ParseDecimalInteger(data, start_pos, len);
5178 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005179 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005180 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005181 } else if (!subject->HasHashCode() &&
5182 len <= String::kMaxArrayIndexSize &&
5183 (len == 1 || data[0] != '0')) {
5184 // String hash is not calculated yet but all the data are present.
5185 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005186 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005187#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005188 subject->Hash(); // Force hash calculation.
5189 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5190 static_cast<int>(hash));
5191#endif
5192 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005193 }
5194 return Smi::FromInt(d);
5195 }
5196 }
5197
5198 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005199 return isolate->heap()->NumberFromDouble(
5200 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201}
5202
5203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005204RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 NoHandleAllocation ha;
5206 ASSERT(args.length() == 1);
5207
5208 CONVERT_CHECKED(JSArray, codes, args[0]);
5209 int length = Smi::cast(codes->length())->value();
5210
5211 // Check if the string can be ASCII.
5212 int i;
5213 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005214 Object* element;
5215 { MaybeObject* maybe_element = codes->GetElement(i);
5216 // We probably can't get an exception here, but just in order to enforce
5217 // the checking of inputs in the runtime calls we check here.
5218 if (!maybe_element->ToObject(&element)) return maybe_element;
5219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5221 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5222 break;
5223 }
5224
lrn@chromium.org303ada72010-10-27 09:33:13 +00005225 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005227 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 }
5231
lrn@chromium.org303ada72010-10-27 09:33:13 +00005232 Object* object = NULL;
5233 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 String* result = String::cast(object);
5235 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005236 Object* element;
5237 { MaybeObject* maybe_element = codes->GetElement(i);
5238 if (!maybe_element->ToObject(&element)) return maybe_element;
5239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005241 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 }
5243 return result;
5244}
5245
5246
5247// kNotEscaped is generated by the following:
5248//
5249// #!/bin/perl
5250// for (my $i = 0; $i < 256; $i++) {
5251// print "\n" if $i % 16 == 0;
5252// my $c = chr($i);
5253// my $escaped = 1;
5254// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5255// print $escaped ? "0, " : "1, ";
5256// }
5257
5258
5259static bool IsNotEscaped(uint16_t character) {
5260 // Only for 8 bit characters, the rest are always escaped (in a different way)
5261 ASSERT(character < 256);
5262 static const char kNotEscaped[256] = {
5263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5265 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5267 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5268 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5269 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5270 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5279 };
5280 return kNotEscaped[character] != 0;
5281}
5282
5283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005284RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 const char hex_chars[] = "0123456789ABCDEF";
5286 NoHandleAllocation ha;
5287 ASSERT(args.length() == 1);
5288 CONVERT_CHECKED(String, source, args[0]);
5289
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005290 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291
5292 int escaped_length = 0;
5293 int length = source->length();
5294 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005295 Access<StringInputBuffer> buffer(
5296 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005297 buffer->Reset(source);
5298 while (buffer->has_more()) {
5299 uint16_t character = buffer->GetNext();
5300 if (character >= 256) {
5301 escaped_length += 6;
5302 } else if (IsNotEscaped(character)) {
5303 escaped_length++;
5304 } else {
5305 escaped_length += 3;
5306 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005307 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005308 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005309 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 return Failure::OutOfMemoryException();
5312 }
5313 }
5314 }
5315 // No length change implies no change. Return original string if no change.
5316 if (escaped_length == length) {
5317 return source;
5318 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005319 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 { MaybeObject* maybe_o =
5321 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005322 if (!maybe_o->ToObject(&o)) return maybe_o;
5323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 String* destination = String::cast(o);
5325 int dest_position = 0;
5326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005327 Access<StringInputBuffer> buffer(
5328 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005329 buffer->Rewind();
5330 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005331 uint16_t chr = buffer->GetNext();
5332 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005333 destination->Set(dest_position, '%');
5334 destination->Set(dest_position+1, 'u');
5335 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5336 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5337 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5338 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005339 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005340 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005341 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 dest_position++;
5343 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005344 destination->Set(dest_position, '%');
5345 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5346 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 dest_position += 3;
5348 }
5349 }
5350 return destination;
5351}
5352
5353
5354static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5355 static const signed char kHexValue['g'] = {
5356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5357 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5358 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5359 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5360 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5361 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5362 -1, 10, 11, 12, 13, 14, 15 };
5363
5364 if (character1 > 'f') return -1;
5365 int hi = kHexValue[character1];
5366 if (hi == -1) return -1;
5367 if (character2 > 'f') return -1;
5368 int lo = kHexValue[character2];
5369 if (lo == -1) return -1;
5370 return (hi << 4) + lo;
5371}
5372
5373
ager@chromium.org870a0b62008-11-04 11:43:05 +00005374static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005375 int i,
5376 int length,
5377 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005378 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005379 int32_t hi = 0;
5380 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381 if (character == '%' &&
5382 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005383 source->Get(i + 1) == 'u' &&
5384 (hi = TwoDigitHex(source->Get(i + 2),
5385 source->Get(i + 3))) != -1 &&
5386 (lo = TwoDigitHex(source->Get(i + 4),
5387 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 *step = 6;
5389 return (hi << 8) + lo;
5390 } else if (character == '%' &&
5391 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005392 (lo = TwoDigitHex(source->Get(i + 1),
5393 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394 *step = 3;
5395 return lo;
5396 } else {
5397 *step = 1;
5398 return character;
5399 }
5400}
5401
5402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005403RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 1);
5406 CONVERT_CHECKED(String, source, args[0]);
5407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005408 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409
5410 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005411 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412
5413 int unescaped_length = 0;
5414 for (int i = 0; i < length; unescaped_length++) {
5415 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005416 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 i += step;
5420 }
5421
5422 // No length change implies no change. Return original string if no change.
5423 if (unescaped_length == length)
5424 return source;
5425
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005427 { MaybeObject* maybe_o =
5428 ascii ?
5429 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5430 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005431 if (!maybe_o->ToObject(&o)) return maybe_o;
5432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 String* destination = String::cast(o);
5434
5435 int dest_position = 0;
5436 for (int i = 0; i < length; dest_position++) {
5437 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 i += step;
5440 }
5441 return destination;
5442}
5443
5444
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005445static const unsigned int kQuoteTableLength = 128u;
5446
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005447static const int kJsonQuotesCharactersPerEntry = 8;
5448static const char* const JsonQuotes =
5449 "\\u0000 \\u0001 \\u0002 \\u0003 "
5450 "\\u0004 \\u0005 \\u0006 \\u0007 "
5451 "\\b \\t \\n \\u000b "
5452 "\\f \\r \\u000e \\u000f "
5453 "\\u0010 \\u0011 \\u0012 \\u0013 "
5454 "\\u0014 \\u0015 \\u0016 \\u0017 "
5455 "\\u0018 \\u0019 \\u001a \\u001b "
5456 "\\u001c \\u001d \\u001e \\u001f "
5457 " ! \\\" # "
5458 "$ % & ' "
5459 "( ) * + "
5460 ", - . / "
5461 "0 1 2 3 "
5462 "4 5 6 7 "
5463 "8 9 : ; "
5464 "< = > ? "
5465 "@ A B C "
5466 "D E F G "
5467 "H I J K "
5468 "L M N O "
5469 "P Q R S "
5470 "T U V W "
5471 "X Y Z [ "
5472 "\\\\ ] ^ _ "
5473 "` a b c "
5474 "d e f g "
5475 "h i j k "
5476 "l m n o "
5477 "p q r s "
5478 "t u v w "
5479 "x y z { "
5480 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005481
5482
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005483// For a string that is less than 32k characters it should always be
5484// possible to allocate it in new space.
5485static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5486
5487
5488// Doing JSON quoting cannot make the string more than this many times larger.
5489static const int kJsonQuoteWorstCaseBlowup = 6;
5490
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005491static const int kSpaceForQuotesAndComma = 3;
5492static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005493
5494// Covers the entire ASCII range (all other characters are unchanged by JSON
5495// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005496static const byte JsonQuoteLengths[kQuoteTableLength] = {
5497 6, 6, 6, 6, 6, 6, 6, 6,
5498 2, 2, 2, 6, 2, 2, 6, 6,
5499 6, 6, 6, 6, 6, 6, 6, 6,
5500 6, 6, 6, 6, 6, 6, 6, 6,
5501 1, 1, 2, 1, 1, 1, 1, 1,
5502 1, 1, 1, 1, 1, 1, 1, 1,
5503 1, 1, 1, 1, 1, 1, 1, 1,
5504 1, 1, 1, 1, 1, 1, 1, 1,
5505 1, 1, 1, 1, 1, 1, 1, 1,
5506 1, 1, 1, 1, 1, 1, 1, 1,
5507 1, 1, 1, 1, 1, 1, 1, 1,
5508 1, 1, 1, 1, 2, 1, 1, 1,
5509 1, 1, 1, 1, 1, 1, 1, 1,
5510 1, 1, 1, 1, 1, 1, 1, 1,
5511 1, 1, 1, 1, 1, 1, 1, 1,
5512 1, 1, 1, 1, 1, 1, 1, 1,
5513};
5514
5515
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005516template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005517MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005518
5519
5520template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005521MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5522 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005523}
5524
5525
5526template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005527MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5528 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005529}
5530
5531
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005532template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005533static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5534 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005535 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005536 const Char* read_cursor = characters.start();
5537 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005538 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005539 int quoted_length = kSpaceForQuotes;
5540 while (read_cursor < end) {
5541 Char c = *(read_cursor++);
5542 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5543 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005544 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005546 }
5547 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005548 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5549 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005550 Object* new_object;
5551 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005552 return new_alloc;
5553 }
5554 StringType* new_string = StringType::cast(new_object);
5555
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005556 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005557 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005558 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005559 *(write_cursor++) = '"';
5560
5561 read_cursor = characters.start();
5562 while (read_cursor < end) {
5563 Char c = *(read_cursor++);
5564 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5565 *(write_cursor++) = c;
5566 } else {
5567 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5568 const char* replacement = JsonQuotes +
5569 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5570 for (int i = 0; i < len; i++) {
5571 *write_cursor++ = *replacement++;
5572 }
5573 }
5574 }
5575 *(write_cursor++) = '"';
5576 return new_string;
5577}
5578
5579
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005580template <typename SinkChar, typename SourceChar>
5581static inline SinkChar* WriteQuoteJsonString(
5582 Isolate* isolate,
5583 SinkChar* write_cursor,
5584 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005585 // SinkChar is only char if SourceChar is guaranteed to be char.
5586 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005587 const SourceChar* read_cursor = characters.start();
5588 const SourceChar* end = read_cursor + characters.length();
5589 *(write_cursor++) = '"';
5590 while (read_cursor < end) {
5591 SourceChar c = *(read_cursor++);
5592 if (sizeof(SourceChar) > 1u &&
5593 static_cast<unsigned>(c) >= kQuoteTableLength) {
5594 *(write_cursor++) = static_cast<SinkChar>(c);
5595 } else {
5596 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5597 const char* replacement = JsonQuotes +
5598 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5599 write_cursor[0] = replacement[0];
5600 if (len > 1) {
5601 write_cursor[1] = replacement[1];
5602 if (len > 2) {
5603 ASSERT(len == 6);
5604 write_cursor[2] = replacement[2];
5605 write_cursor[3] = replacement[3];
5606 write_cursor[4] = replacement[4];
5607 write_cursor[5] = replacement[5];
5608 }
5609 }
5610 write_cursor += len;
5611 }
5612 }
5613 *(write_cursor++) = '"';
5614 return write_cursor;
5615}
5616
5617
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005618template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619static MaybeObject* QuoteJsonString(Isolate* isolate,
5620 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005621 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005622 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005623 int worst_case_length =
5624 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005625 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 }
5628
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5630 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005631 Object* new_object;
5632 if (!new_alloc->ToObject(&new_object)) {
5633 return new_alloc;
5634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005636 // Even if our string is small enough to fit in new space we still have to
5637 // handle it being allocated in old space as may happen in the third
5638 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5639 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005640 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641 }
5642 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005646 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005647 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005648 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5649 write_cursor,
5650 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005651 int final_length = static_cast<int>(
5652 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005653 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005654 isolate->heap()->new_space()->
5655 template ShrinkStringAtAllocationBoundary<StringType>(
5656 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005657 return new_string;
5658}
5659
5660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005661RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 NoHandleAllocation ha;
5663 CONVERT_CHECKED(String, str, args[0]);
5664 if (!str->IsFlat()) {
5665 MaybeObject* try_flatten = str->TryFlatten();
5666 Object* flat;
5667 if (!try_flatten->ToObject(&flat)) {
5668 return try_flatten;
5669 }
5670 str = String::cast(flat);
5671 ASSERT(str->IsFlat());
5672 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005673 String::FlatContent flat = str->GetFlatContent();
5674 ASSERT(flat.IsFlat());
5675 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005677 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005680 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005681 }
5682}
5683
5684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005685RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005686 NoHandleAllocation ha;
5687 CONVERT_CHECKED(String, str, args[0]);
5688 if (!str->IsFlat()) {
5689 MaybeObject* try_flatten = str->TryFlatten();
5690 Object* flat;
5691 if (!try_flatten->ToObject(&flat)) {
5692 return try_flatten;
5693 }
5694 str = String::cast(flat);
5695 ASSERT(str->IsFlat());
5696 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005697 String::FlatContent flat = str->GetFlatContent();
5698 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005700 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005702 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005703 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005704 }
5705}
5706
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005707
5708template <typename Char, typename StringType>
5709static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5710 FixedArray* array,
5711 int worst_case_length) {
5712 int length = array->length();
5713
5714 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5715 worst_case_length);
5716 Object* new_object;
5717 if (!new_alloc->ToObject(&new_object)) {
5718 return new_alloc;
5719 }
5720 if (!isolate->heap()->new_space()->Contains(new_object)) {
5721 // Even if our string is small enough to fit in new space we still have to
5722 // handle it being allocated in old space as may happen in the third
5723 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5724 // CEntryStub::GenerateCore.
5725 return isolate->heap()->undefined_value();
5726 }
5727 AssertNoAllocation no_gc;
5728 StringType* new_string = StringType::cast(new_object);
5729 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5730
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005731 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005732 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 *(write_cursor++) = '[';
5734 for (int i = 0; i < length; i++) {
5735 if (i != 0) *(write_cursor++) = ',';
5736 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005737 String::FlatContent content = str->GetFlatContent();
5738 ASSERT(content.IsFlat());
5739 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005740 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5741 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005742 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005743 } else {
5744 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5745 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005746 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005747 }
5748 }
5749 *(write_cursor++) = ']';
5750
5751 int final_length = static_cast<int>(
5752 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005753 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005754 isolate->heap()->new_space()->
5755 template ShrinkStringAtAllocationBoundary<StringType>(
5756 new_string, final_length);
5757 return new_string;
5758}
5759
5760
5761RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5762 NoHandleAllocation ha;
5763 ASSERT(args.length() == 1);
5764 CONVERT_CHECKED(JSArray, array, args[0]);
5765
5766 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5767 FixedArray* elements = FixedArray::cast(array->elements());
5768 int n = elements->length();
5769 bool ascii = true;
5770 int total_length = 0;
5771
5772 for (int i = 0; i < n; i++) {
5773 Object* elt = elements->get(i);
5774 if (!elt->IsString()) return isolate->heap()->undefined_value();
5775 String* element = String::cast(elt);
5776 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5777 total_length += element->length();
5778 if (ascii && element->IsTwoByteRepresentation()) {
5779 ascii = false;
5780 }
5781 }
5782
5783 int worst_case_length =
5784 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5785 + total_length * kJsonQuoteWorstCaseBlowup;
5786
5787 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5788 return isolate->heap()->undefined_value();
5789 }
5790
5791 if (ascii) {
5792 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5793 elements,
5794 worst_case_length);
5795 } else {
5796 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5797 elements,
5798 worst_case_length);
5799 }
5800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804 NoHandleAllocation ha;
5805
5806 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005807 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005810
lrn@chromium.org25156de2010-04-06 13:10:27 +00005811 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005812 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005817RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818 NoHandleAllocation ha;
5819 CONVERT_CHECKED(String, str, args[0]);
5820
5821 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005822 double value = StringToDouble(isolate->unicode_cache(),
5823 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824
5825 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005827}
5828
5829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005830template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005831MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005832 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005833 String* s,
5834 int length,
5835 int input_string_length,
5836 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005837 // We try this twice, once with the assumption that the result is no longer
5838 // than the input and, if that assumption breaks, again with the exact
5839 // length. This may not be pretty, but it is nicer than what was here before
5840 // and I hereby claim my vaffel-is.
5841 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842 // Allocate the resulting string.
5843 //
5844 // NOTE: This assumes that the upper/lower case of an ascii
5845 // character is also ascii. This is currently the case, but it
5846 // might break in the future if we implement more context and locale
5847 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005848 Object* o;
5849 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 ? isolate->heap()->AllocateRawAsciiString(length)
5851 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005852 if (!maybe_o->ToObject(&o)) return maybe_o;
5853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854 String* result = String::cast(o);
5855 bool has_changed_character = false;
5856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005857 // Convert all characters to upper case, assuming that they will fit
5858 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005859 Access<StringInputBuffer> buffer(
5860 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005862 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005863 // We can assume that the string is not empty
5864 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005865 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005866 bool has_next = buffer->has_more();
5867 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 int char_length = mapping->get(current, next, chars);
5869 if (char_length == 0) {
5870 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005871 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872 i++;
5873 } else if (char_length == 1) {
5874 // Common case: converting the letter resulted in one character.
5875 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005876 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005877 has_changed_character = true;
5878 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005879 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880 // We've assumed that the result would be as long as the
5881 // input but here is a character that converts to several
5882 // characters. No matter, we calculate the exact length
5883 // of the result and try the whole thing again.
5884 //
5885 // Note that this leaves room for optimization. We could just
5886 // memcpy what we already have to the result string. Also,
5887 // the result string is the last object allocated we could
5888 // "realloc" it and probably, in the vast majority of cases,
5889 // extend the existing string to be able to hold the full
5890 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005891 int next_length = 0;
5892 if (has_next) {
5893 next_length = mapping->get(next, 0, chars);
5894 if (next_length == 0) next_length = 1;
5895 }
5896 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897 while (buffer->has_more()) {
5898 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005899 // NOTE: we use 0 as the next character here because, while
5900 // the next character may affect what a character converts to,
5901 // it does not in any case affect the length of what it convert
5902 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 int char_length = mapping->get(current, 0, chars);
5904 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005905 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005906 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005907 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005908 return Failure::OutOfMemoryException();
5909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005910 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005911 // Try again with the real length.
5912 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913 } else {
5914 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005915 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 i++;
5917 }
5918 has_changed_character = true;
5919 }
5920 current = next;
5921 }
5922 if (has_changed_character) {
5923 return result;
5924 } else {
5925 // If we didn't actually change anything in doing the conversion
5926 // we simple return the result and let the converted string
5927 // become garbage; there is no reason to keep two identical strings
5928 // alive.
5929 return s;
5930 }
5931}
5932
5933
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005934namespace {
5935
lrn@chromium.org303ada72010-10-27 09:33:13 +00005936static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5937
5938
5939// Given a word and two range boundaries returns a word with high bit
5940// set in every byte iff the corresponding input byte was strictly in
5941// the range (m, n). All the other bits in the result are cleared.
5942// This function is only useful when it can be inlined and the
5943// boundaries are statically known.
5944// Requires: all bytes in the input word and the boundaries must be
5945// ascii (less than 0x7F).
5946static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5947 // Every byte in an ascii string is less than or equal to 0x7F.
5948 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5949 // Use strict inequalities since in edge cases the function could be
5950 // further simplified.
5951 ASSERT(0 < m && m < n && n < 0x7F);
5952 // Has high bit set in every w byte less than n.
5953 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5954 // Has high bit set in every w byte greater than m.
5955 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5956 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5957}
5958
5959
5960enum AsciiCaseConversion {
5961 ASCII_TO_LOWER,
5962 ASCII_TO_UPPER
5963};
5964
5965
5966template <AsciiCaseConversion dir>
5967struct FastAsciiConverter {
5968 static bool Convert(char* dst, char* src, int length) {
5969#ifdef DEBUG
5970 char* saved_dst = dst;
5971 char* saved_src = src;
5972#endif
5973 // We rely on the distance between upper and lower case letters
5974 // being a known power of 2.
5975 ASSERT('a' - 'A' == (1 << 5));
5976 // Boundaries for the range of input characters than require conversion.
5977 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5978 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5979 bool changed = false;
5980 char* const limit = src + length;
5981#ifdef V8_HOST_CAN_READ_UNALIGNED
5982 // Process the prefix of the input that requires no conversion one
5983 // (machine) word at a time.
5984 while (src <= limit - sizeof(uintptr_t)) {
5985 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5986 if (AsciiRangeMask(w, lo, hi) != 0) {
5987 changed = true;
5988 break;
5989 }
5990 *reinterpret_cast<uintptr_t*>(dst) = w;
5991 src += sizeof(uintptr_t);
5992 dst += sizeof(uintptr_t);
5993 }
5994 // Process the remainder of the input performing conversion when
5995 // required one word at a time.
5996 while (src <= limit - sizeof(uintptr_t)) {
5997 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5998 uintptr_t m = AsciiRangeMask(w, lo, hi);
5999 // The mask has high (7th) bit set in every byte that needs
6000 // conversion and we know that the distance between cases is
6001 // 1 << 5.
6002 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6003 src += sizeof(uintptr_t);
6004 dst += sizeof(uintptr_t);
6005 }
6006#endif
6007 // Process the last few bytes of the input (or the whole input if
6008 // unaligned access is not supported).
6009 while (src < limit) {
6010 char c = *src;
6011 if (lo < c && c < hi) {
6012 c ^= (1 << 5);
6013 changed = true;
6014 }
6015 *dst = c;
6016 ++src;
6017 ++dst;
6018 }
6019#ifdef DEBUG
6020 CheckConvert(saved_dst, saved_src, length, changed);
6021#endif
6022 return changed;
6023 }
6024
6025#ifdef DEBUG
6026 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6027 bool expected_changed = false;
6028 for (int i = 0; i < length; i++) {
6029 if (dst[i] == src[i]) continue;
6030 expected_changed = true;
6031 if (dir == ASCII_TO_LOWER) {
6032 ASSERT('A' <= src[i] && src[i] <= 'Z');
6033 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6034 } else {
6035 ASSERT(dir == ASCII_TO_UPPER);
6036 ASSERT('a' <= src[i] && src[i] <= 'z');
6037 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6038 }
6039 }
6040 ASSERT(expected_changed == changed);
6041 }
6042#endif
6043};
6044
6045
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006046struct ToLowerTraits {
6047 typedef unibrow::ToLowercase UnibrowConverter;
6048
lrn@chromium.org303ada72010-10-27 09:33:13 +00006049 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006050};
6051
6052
6053struct ToUpperTraits {
6054 typedef unibrow::ToUppercase UnibrowConverter;
6055
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006057};
6058
6059} // namespace
6060
6061
6062template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006063MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006064 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006066 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006067 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006068 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006069 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006070
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006071 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006072 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073 if (length == 0) return s;
6074
6075 // Simpler handling of ascii strings.
6076 //
6077 // NOTE: This assumes that the upper/lower case of an ascii
6078 // character is also ascii. This is currently the case, but it
6079 // might break in the future if we implement more context and locale
6080 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006081 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006082 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006084 if (!maybe_o->ToObject(&o)) return maybe_o;
6085 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006086 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006087 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006088 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006089 return has_changed_character ? result : s;
6090 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006091
lrn@chromium.org303ada72010-10-27 09:33:13 +00006092 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093 { MaybeObject* maybe_answer =
6094 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006095 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6096 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006097 if (answer->IsSmi()) {
6098 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006099 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006100 ConvertCaseHelper(isolate,
6101 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006102 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6103 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006104 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006105 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006106}
6107
6108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 return ConvertCase<ToLowerTraits>(
6111 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006112}
6113
6114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006115RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 return ConvertCase<ToUpperTraits>(
6117 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118}
6119
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006121static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006122 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006123}
6124
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006126RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006127 NoHandleAllocation ha;
6128 ASSERT(args.length() == 3);
6129
6130 CONVERT_CHECKED(String, s, args[0]);
6131 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6132 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6133
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006134 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006135 int length = s->length();
6136
6137 int left = 0;
6138 if (trimLeft) {
6139 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6140 left++;
6141 }
6142 }
6143
6144 int right = length;
6145 if (trimRight) {
6146 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6147 right--;
6148 }
6149 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006150 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006151}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006154RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006155 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006157 CONVERT_ARG_CHECKED(String, subject, 0);
6158 CONVERT_ARG_CHECKED(String, pattern, 1);
6159 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6160
6161 int subject_length = subject->length();
6162 int pattern_length = pattern->length();
6163 RUNTIME_ASSERT(pattern_length > 0);
6164
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006165 if (limit == 0xffffffffu) {
6166 Handle<Object> cached_answer(StringSplitCache::Lookup(
6167 isolate->heap()->string_split_cache(),
6168 *subject,
6169 *pattern));
6170 if (*cached_answer != Smi::FromInt(0)) {
6171 Handle<JSArray> result =
6172 isolate->factory()->NewJSArrayWithElements(
6173 Handle<FixedArray>::cast(cached_answer));
6174 return *result;
6175 }
6176 }
6177
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006178 // The limit can be very large (0xffffffffu), but since the pattern
6179 // isn't empty, we can never create more parts than ~half the length
6180 // of the subject.
6181
6182 if (!subject->IsFlat()) FlattenString(subject);
6183
6184 static const int kMaxInitialListCapacity = 16;
6185
danno@chromium.org40cb8782011-05-25 07:58:50 +00006186 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006187
6188 // Find (up to limit) indices of separator and end-of-string in subject
6189 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6190 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006191 if (!pattern->IsFlat()) FlattenString(pattern);
6192
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006193 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006194
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006195 if (static_cast<uint32_t>(indices.length()) < limit) {
6196 indices.Add(subject_length);
6197 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006198
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006199 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006200
6201 // Create JSArray of substrings separated by separator.
6202 int part_count = indices.length();
6203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006204 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006205 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6206 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006207 result->set_length(Smi::FromInt(part_count));
6208
6209 ASSERT(result->HasFastElements());
6210
6211 if (part_count == 1 && indices.at(0) == subject_length) {
6212 FixedArray::cast(result->elements())->set(0, *subject);
6213 return *result;
6214 }
6215
6216 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6217 int part_start = 0;
6218 for (int i = 0; i < part_count; i++) {
6219 HandleScope local_loop_handle;
6220 int part_end = indices.at(i);
6221 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006222 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006223 elements->set(i, *substring);
6224 part_start = part_end + pattern_length;
6225 }
6226
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006227 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006228 if (result->HasFastElements()) {
6229 StringSplitCache::Enter(isolate->heap(),
6230 isolate->heap()->string_split_cache(),
6231 *subject,
6232 *pattern,
6233 *elements);
6234 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006235 }
6236
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006237 return *result;
6238}
6239
6240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241// Copies ascii characters to the given fixed array looking up
6242// one-char strings in the cache. Gives up on the first char that is
6243// not in the cache and fills the remainder with smi zeros. Returns
6244// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006245static int CopyCachedAsciiCharsToArray(Heap* heap,
6246 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 FixedArray* elements,
6248 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006249 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 FixedArray* ascii_cache = heap->single_character_string_cache();
6251 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006253 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254 for (i = 0; i < length; ++i) {
6255 Object* value = ascii_cache->get(chars[i]);
6256 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006257 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006258 }
6259 if (i < length) {
6260 ASSERT(Smi::FromInt(0) == 0);
6261 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6262 }
6263#ifdef DEBUG
6264 for (int j = 0; j < length; ++j) {
6265 Object* element = elements->get(j);
6266 ASSERT(element == Smi::FromInt(0) ||
6267 (element->IsString() && String::cast(element)->LooksValid()));
6268 }
6269#endif
6270 return i;
6271}
6272
6273
6274// Converts a String to JSArray.
6275// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006277 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006278 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006279 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006280 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006281
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006282 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006283 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284
6285 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006286 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006287 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006288 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006289 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 { MaybeObject* maybe_obj =
6291 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6293 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006294 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006295 String::FlatContent content = s->GetFlatContent();
6296 if (content.IsAscii()) {
6297 Vector<const char> chars = content.ToAsciiVector();
6298 // Note, this will initialize all elements (not only the prefix)
6299 // to prevent GC from seeing partially initialized array.
6300 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6301 chars.start(),
6302 *elements,
6303 length);
6304 } else {
6305 MemsetPointer(elements->data_start(),
6306 isolate->heap()->undefined_value(),
6307 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006308 }
6309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006310 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006311 }
6312 for (int i = position; i < length; ++i) {
6313 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6314 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006315 }
6316
6317#ifdef DEBUG
6318 for (int i = 0; i < length; ++i) {
6319 ASSERT(String::cast(elements->get(i))->length() == 1);
6320 }
6321#endif
6322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006323 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006324}
6325
6326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006327RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006328 NoHandleAllocation ha;
6329 ASSERT(args.length() == 1);
6330 CONVERT_CHECKED(String, value, args[0]);
6331 return value->ToObject();
6332}
6333
6334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006336 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006338 return char_length == 0;
6339}
6340
6341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006342RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 NoHandleAllocation ha;
6344 ASSERT(args.length() == 1);
6345
6346 Object* number = args[0];
6347 RUNTIME_ASSERT(number->IsNumber());
6348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350}
6351
6352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006353RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006354 NoHandleAllocation ha;
6355 ASSERT(args.length() == 1);
6356
6357 Object* number = args[0];
6358 RUNTIME_ASSERT(number->IsNumber());
6359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006361}
6362
6363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006364RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365 NoHandleAllocation ha;
6366 ASSERT(args.length() == 1);
6367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006368 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369
6370 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6371 if (number > 0 && number <= Smi::kMaxValue) {
6372 return Smi::FromInt(static_cast<int>(number));
6373 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006378RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 1);
6381
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006382 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006383
6384 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6385 if (number > 0 && number <= Smi::kMaxValue) {
6386 return Smi::FromInt(static_cast<int>(number));
6387 }
6388
6389 double double_value = DoubleToInteger(number);
6390 // Map both -0 and +0 to +0.
6391 if (double_value == 0) double_value = 0;
6392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006393 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006394}
6395
6396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006397RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 NoHandleAllocation ha;
6399 ASSERT(args.length() == 1);
6400
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006402 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403}
6404
6405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006406RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006407 NoHandleAllocation ha;
6408 ASSERT(args.length() == 1);
6409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006410 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006411
6412 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6413 if (number > 0 && number <= Smi::kMaxValue) {
6414 return Smi::FromInt(static_cast<int>(number));
6415 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417}
6418
6419
ager@chromium.org870a0b62008-11-04 11:43:05 +00006420// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6421// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006422RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006423 NoHandleAllocation ha;
6424 ASSERT(args.length() == 1);
6425
6426 Object* obj = args[0];
6427 if (obj->IsSmi()) {
6428 return obj;
6429 }
6430 if (obj->IsHeapNumber()) {
6431 double value = HeapNumber::cast(obj)->value();
6432 int int_value = FastD2I(value);
6433 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6434 return Smi::FromInt(int_value);
6435 }
6436 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006438}
6439
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006441RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006442 NoHandleAllocation ha;
6443 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006445}
6446
6447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006448RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 NoHandleAllocation ha;
6450 ASSERT(args.length() == 2);
6451
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006452 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6453 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455}
6456
6457
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006458RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459 NoHandleAllocation ha;
6460 ASSERT(args.length() == 2);
6461
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006462 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6463 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006465}
6466
6467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006468RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469 NoHandleAllocation ha;
6470 ASSERT(args.length() == 2);
6471
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006472 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6473 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475}
6476
6477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006478RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479 NoHandleAllocation ha;
6480 ASSERT(args.length() == 1);
6481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006483 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484}
6485
6486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006487RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006488 NoHandleAllocation ha;
6489 ASSERT(args.length() == 0);
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 2);
6498
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006499 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6500 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006505RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006506 NoHandleAllocation ha;
6507 ASSERT(args.length() == 2);
6508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006509 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6510 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511
ager@chromium.org3811b432009-10-28 14:53:37 +00006512 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006513 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 CONVERT_CHECKED(String, str1, args[0]);
6522 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006523 isolate->counters()->string_add_runtime()->Increment();
6524 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006528template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006529static inline void StringBuilderConcatHelper(String* special,
6530 sinkchar* sink,
6531 FixedArray* fixed_array,
6532 int array_length) {
6533 int position = 0;
6534 for (int i = 0; i < array_length; i++) {
6535 Object* element = fixed_array->get(i);
6536 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006537 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006538 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006539 int pos;
6540 int len;
6541 if (encoded_slice > 0) {
6542 // Position and length encoded in one smi.
6543 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6544 len = StringBuilderSubstringLength::decode(encoded_slice);
6545 } else {
6546 // Position and length encoded in two smis.
6547 Object* obj = fixed_array->get(++i);
6548 ASSERT(obj->IsSmi());
6549 pos = Smi::cast(obj)->value();
6550 len = -encoded_slice;
6551 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006552 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006553 sink + position,
6554 pos,
6555 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006556 position += len;
6557 } else {
6558 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006559 int element_length = string->length();
6560 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006561 position += element_length;
6562 }
6563 }
6564}
6565
6566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006567RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006569 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006571 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006573 return Failure::OutOfMemoryException();
6574 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006575 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006576 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006577
6578 // This assumption is used by the slice encoding in one or two smis.
6579 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006581 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6582 if (maybe_result->IsFailure()) return maybe_result;
6583
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006584 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 }
6588 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006589 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006591 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592
6593 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595 } else if (array_length == 1) {
6596 Object* first = fixed_array->get(0);
6597 if (first->IsString()) return first;
6598 }
6599
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006600 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 int position = 0;
6602 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006603 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 Object* elt = fixed_array->get(i);
6605 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006606 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006607 int smi_value = Smi::cast(elt)->value();
6608 int pos;
6609 int len;
6610 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006611 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006612 pos = StringBuilderSubstringPosition::decode(smi_value);
6613 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006614 } else {
6615 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006616 len = -smi_value;
6617 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006618 i++;
6619 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006620 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006621 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006622 Object* next_smi = fixed_array->get(i);
6623 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006625 }
6626 pos = Smi::cast(next_smi)->value();
6627 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006631 ASSERT(pos >= 0);
6632 ASSERT(len >= 0);
6633 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006634 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006635 }
6636 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 } else if (elt->IsString()) {
6638 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006639 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006640 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006641 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006645 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006647 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006648 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006649 return Failure::OutOfMemoryException();
6650 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006651 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 }
6653
6654 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006658 { MaybeObject* maybe_object =
6659 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006660 if (!maybe_object->ToObject(&object)) return maybe_object;
6661 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006662 SeqAsciiString* answer = SeqAsciiString::cast(object);
6663 StringBuilderConcatHelper(special,
6664 answer->GetChars(),
6665 fixed_array,
6666 array_length);
6667 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006669 { MaybeObject* maybe_object =
6670 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006671 if (!maybe_object->ToObject(&object)) return maybe_object;
6672 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006673 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6674 StringBuilderConcatHelper(special,
6675 answer->GetChars(),
6676 fixed_array,
6677 array_length);
6678 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680}
6681
6682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006683RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006684 NoHandleAllocation ha;
6685 ASSERT(args.length() == 3);
6686 CONVERT_CHECKED(JSArray, array, args[0]);
6687 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006689 return Failure::OutOfMemoryException();
6690 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006691 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006692 CONVERT_CHECKED(String, separator, args[2]);
6693
6694 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006696 }
6697 FixedArray* fixed_array = FixedArray::cast(array->elements());
6698 if (fixed_array->length() < array_length) {
6699 array_length = fixed_array->length();
6700 }
6701
6702 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006704 } else if (array_length == 1) {
6705 Object* first = fixed_array->get(0);
6706 if (first->IsString()) return first;
6707 }
6708
6709 int separator_length = separator->length();
6710 int max_nof_separators =
6711 (String::kMaxLength + separator_length - 1) / separator_length;
6712 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006714 return Failure::OutOfMemoryException();
6715 }
6716 int length = (array_length - 1) * separator_length;
6717 for (int i = 0; i < array_length; i++) {
6718 Object* element_obj = fixed_array->get(i);
6719 if (!element_obj->IsString()) {
6720 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006722 }
6723 String* element = String::cast(element_obj);
6724 int increment = element->length();
6725 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006727 return Failure::OutOfMemoryException();
6728 }
6729 length += increment;
6730 }
6731
6732 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 { MaybeObject* maybe_object =
6734 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006735 if (!maybe_object->ToObject(&object)) return maybe_object;
6736 }
6737 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6738
6739 uc16* sink = answer->GetChars();
6740#ifdef DEBUG
6741 uc16* end = sink + length;
6742#endif
6743
6744 String* first = String::cast(fixed_array->get(0));
6745 int first_length = first->length();
6746 String::WriteToFlat(first, sink, 0, first_length);
6747 sink += first_length;
6748
6749 for (int i = 1; i < array_length; i++) {
6750 ASSERT(sink + separator_length <= end);
6751 String::WriteToFlat(separator, sink, 0, separator_length);
6752 sink += separator_length;
6753
6754 String* element = String::cast(fixed_array->get(i));
6755 int element_length = element->length();
6756 ASSERT(sink + element_length <= end);
6757 String::WriteToFlat(element, sink, 0, element_length);
6758 sink += element_length;
6759 }
6760 ASSERT(sink == end);
6761
6762 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6763 return answer;
6764}
6765
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006766template <typename Char>
6767static void JoinSparseArrayWithSeparator(FixedArray* elements,
6768 int elements_length,
6769 uint32_t array_length,
6770 String* separator,
6771 Vector<Char> buffer) {
6772 int previous_separator_position = 0;
6773 int separator_length = separator->length();
6774 int cursor = 0;
6775 for (int i = 0; i < elements_length; i += 2) {
6776 int position = NumberToInt32(elements->get(i));
6777 String* string = String::cast(elements->get(i + 1));
6778 int string_length = string->length();
6779 if (string->length() > 0) {
6780 while (previous_separator_position < position) {
6781 String::WriteToFlat<Char>(separator, &buffer[cursor],
6782 0, separator_length);
6783 cursor += separator_length;
6784 previous_separator_position++;
6785 }
6786 String::WriteToFlat<Char>(string, &buffer[cursor],
6787 0, string_length);
6788 cursor += string->length();
6789 }
6790 }
6791 if (separator_length > 0) {
6792 // Array length must be representable as a signed 32-bit number,
6793 // otherwise the total string length would have been too large.
6794 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6795 int last_array_index = static_cast<int>(array_length - 1);
6796 while (previous_separator_position < last_array_index) {
6797 String::WriteToFlat<Char>(separator, &buffer[cursor],
6798 0, separator_length);
6799 cursor += separator_length;
6800 previous_separator_position++;
6801 }
6802 }
6803 ASSERT(cursor <= buffer.length());
6804}
6805
6806
6807RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6808 NoHandleAllocation ha;
6809 ASSERT(args.length() == 3);
6810 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006811 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6812 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006813 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6814 CONVERT_CHECKED(String, separator, args[2]);
6815 // elements_array is fast-mode JSarray of alternating positions
6816 // (increasing order) and strings.
6817 // array_length is length of original array (used to add separators);
6818 // separator is string to put between elements. Assumed to be non-empty.
6819
6820 // Find total length of join result.
6821 int string_length = 0;
6822 bool is_ascii = true;
6823 int max_string_length = SeqAsciiString::kMaxLength;
6824 bool overflow = false;
6825 CONVERT_NUMBER_CHECKED(int, elements_length,
6826 Int32, elements_array->length());
6827 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6828 FixedArray* elements = FixedArray::cast(elements_array->elements());
6829 for (int i = 0; i < elements_length; i += 2) {
6830 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6831 CONVERT_CHECKED(String, string, elements->get(i + 1));
6832 int length = string->length();
6833 if (is_ascii && !string->IsAsciiRepresentation()) {
6834 is_ascii = false;
6835 max_string_length = SeqTwoByteString::kMaxLength;
6836 }
6837 if (length > max_string_length ||
6838 max_string_length - length < string_length) {
6839 overflow = true;
6840 break;
6841 }
6842 string_length += length;
6843 }
6844 int separator_length = separator->length();
6845 if (!overflow && separator_length > 0) {
6846 if (array_length <= 0x7fffffffu) {
6847 int separator_count = static_cast<int>(array_length) - 1;
6848 int remaining_length = max_string_length - string_length;
6849 if ((remaining_length / separator_length) >= separator_count) {
6850 string_length += separator_length * (array_length - 1);
6851 } else {
6852 // Not room for the separators within the maximal string length.
6853 overflow = true;
6854 }
6855 } else {
6856 // Nonempty separator and at least 2^31-1 separators necessary
6857 // means that the string is too large to create.
6858 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6859 overflow = true;
6860 }
6861 }
6862 if (overflow) {
6863 // Throw OutOfMemory exception for creating too large a string.
6864 V8::FatalProcessOutOfMemory("Array join result too large.");
6865 }
6866
6867 if (is_ascii) {
6868 MaybeObject* result_allocation =
6869 isolate->heap()->AllocateRawAsciiString(string_length);
6870 if (result_allocation->IsFailure()) return result_allocation;
6871 SeqAsciiString* result_string =
6872 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6873 JoinSparseArrayWithSeparator<char>(elements,
6874 elements_length,
6875 array_length,
6876 separator,
6877 Vector<char>(result_string->GetChars(),
6878 string_length));
6879 return result_string;
6880 } else {
6881 MaybeObject* result_allocation =
6882 isolate->heap()->AllocateRawTwoByteString(string_length);
6883 if (result_allocation->IsFailure()) return result_allocation;
6884 SeqTwoByteString* result_string =
6885 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6886 JoinSparseArrayWithSeparator<uc16>(elements,
6887 elements_length,
6888 array_length,
6889 separator,
6890 Vector<uc16>(result_string->GetChars(),
6891 string_length));
6892 return result_string;
6893 }
6894}
6895
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006897RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006898 NoHandleAllocation ha;
6899 ASSERT(args.length() == 2);
6900
6901 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6902 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006903 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904}
6905
6906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006907RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006908 NoHandleAllocation ha;
6909 ASSERT(args.length() == 2);
6910
6911 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6912 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006913 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914}
6915
6916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006917RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006918 NoHandleAllocation ha;
6919 ASSERT(args.length() == 2);
6920
6921 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6922 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924}
6925
6926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006927RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 NoHandleAllocation ha;
6929 ASSERT(args.length() == 1);
6930
6931 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933}
6934
6935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006936RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006937 NoHandleAllocation ha;
6938 ASSERT(args.length() == 2);
6939
6940 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6941 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943}
6944
6945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006946RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 NoHandleAllocation ha;
6948 ASSERT(args.length() == 2);
6949
6950 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6951 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006952 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953}
6954
6955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006956RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 NoHandleAllocation ha;
6958 ASSERT(args.length() == 2);
6959
6960 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6961 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006962 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963}
6964
6965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006966RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 NoHandleAllocation ha;
6968 ASSERT(args.length() == 2);
6969
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006970 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6971 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6973 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6974 if (x == y) return Smi::FromInt(EQUAL);
6975 Object* result;
6976 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6977 result = Smi::FromInt(EQUAL);
6978 } else {
6979 result = Smi::FromInt(NOT_EQUAL);
6980 }
6981 return result;
6982}
6983
6984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006985RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 NoHandleAllocation ha;
6987 ASSERT(args.length() == 2);
6988
6989 CONVERT_CHECKED(String, x, args[0]);
6990 CONVERT_CHECKED(String, y, args[1]);
6991
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006992 bool not_equal = !x->Equals(y);
6993 // This is slightly convoluted because the value that signifies
6994 // equality is 0 and inequality is 1 so we have to negate the result
6995 // from String::Equals.
6996 ASSERT(not_equal == 0 || not_equal == 1);
6997 STATIC_CHECK(EQUAL == 0);
6998 STATIC_CHECK(NOT_EQUAL == 1);
6999 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000}
7001
7002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007003RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004 NoHandleAllocation ha;
7005 ASSERT(args.length() == 3);
7006
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007007 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7008 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 if (isnan(x) || isnan(y)) return args[2];
7010 if (x == y) return Smi::FromInt(EQUAL);
7011 if (isless(x, y)) return Smi::FromInt(LESS);
7012 return Smi::FromInt(GREATER);
7013}
7014
7015
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007016// Compare two Smis as if they were converted to strings and then
7017// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 2);
7021
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007022 // Extract the integer values from the Smis.
7023 CONVERT_CHECKED(Smi, x, args[0]);
7024 CONVERT_CHECKED(Smi, y, args[1]);
7025 int x_value = x->value();
7026 int y_value = y->value();
7027
7028 // If the integers are equal so are the string representations.
7029 if (x_value == y_value) return Smi::FromInt(EQUAL);
7030
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007031 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007032 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007033 if (x_value == 0 || y_value == 0)
7034 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007035
ager@chromium.org32912102009-01-16 10:38:43 +00007036 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007037 // smallest because the char code of '-' is less than the char code
7038 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007039
7040 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7041 // architectures using 32-bit Smis.
7042 uint32_t x_scaled = x_value;
7043 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007044 if (x_value < 0 || y_value < 0) {
7045 if (y_value >= 0) return Smi::FromInt(LESS);
7046 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007047 x_scaled = -x_value;
7048 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007049 }
7050
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007051 static const uint32_t kPowersOf10[] = {
7052 1, 10, 100, 1000, 10*1000, 100*1000,
7053 1000*1000, 10*1000*1000, 100*1000*1000,
7054 1000*1000*1000
7055 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007057 // If the integers have the same number of decimal digits they can be
7058 // compared directly as the numeric order is the same as the
7059 // lexicographic order. If one integer has fewer digits, it is scaled
7060 // by some power of 10 to have the same number of digits as the longer
7061 // integer. If the scaled integers are equal it means the shorter
7062 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007064 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7065 int x_log2 = IntegerLog2(x_scaled);
7066 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7067 x_log10 -= x_scaled < kPowersOf10[x_log10];
7068
7069 int y_log2 = IntegerLog2(y_scaled);
7070 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7071 y_log10 -= y_scaled < kPowersOf10[y_log10];
7072
7073 int tie = EQUAL;
7074
7075 if (x_log10 < y_log10) {
7076 // X has fewer digits. We would like to simply scale up X but that
7077 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7078 // be scaled up to 9_000_000_000. So we scale up by the next
7079 // smallest power and scale down Y to drop one digit. It is OK to
7080 // drop one digit from the longer integer since the final digit is
7081 // past the length of the shorter integer.
7082 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7083 y_scaled /= 10;
7084 tie = LESS;
7085 } else if (y_log10 < x_log10) {
7086 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7087 x_scaled /= 10;
7088 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007089 }
7090
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007091 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7092 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7093 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007094}
7095
7096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097static Object* StringInputBufferCompare(RuntimeState* state,
7098 String* x,
7099 String* y) {
7100 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7101 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007102 bufx.Reset(x);
7103 bufy.Reset(y);
7104 while (bufx.has_more() && bufy.has_more()) {
7105 int d = bufx.GetNext() - bufy.GetNext();
7106 if (d < 0) return Smi::FromInt(LESS);
7107 else if (d > 0) return Smi::FromInt(GREATER);
7108 }
7109
7110 // x is (non-trivial) prefix of y:
7111 if (bufy.has_more()) return Smi::FromInt(LESS);
7112 // y is prefix of x:
7113 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7114}
7115
7116
7117static Object* FlatStringCompare(String* x, String* y) {
7118 ASSERT(x->IsFlat());
7119 ASSERT(y->IsFlat());
7120 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7121 int prefix_length = x->length();
7122 if (y->length() < prefix_length) {
7123 prefix_length = y->length();
7124 equal_prefix_result = Smi::FromInt(GREATER);
7125 } else if (y->length() > prefix_length) {
7126 equal_prefix_result = Smi::FromInt(LESS);
7127 }
7128 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007129 String::FlatContent x_content = x->GetFlatContent();
7130 String::FlatContent y_content = y->GetFlatContent();
7131 if (x_content.IsAscii()) {
7132 Vector<const char> x_chars = x_content.ToAsciiVector();
7133 if (y_content.IsAscii()) {
7134 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007135 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007136 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007137 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007138 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7139 }
7140 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007141 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7142 if (y_content.IsAscii()) {
7143 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007144 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7145 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007146 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007147 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7148 }
7149 }
7150 Object* result;
7151 if (r == 0) {
7152 result = equal_prefix_result;
7153 } else {
7154 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7155 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007156 ASSERT(result ==
7157 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007158 return result;
7159}
7160
7161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007162RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163 NoHandleAllocation ha;
7164 ASSERT(args.length() == 2);
7165
7166 CONVERT_CHECKED(String, x, args[0]);
7167 CONVERT_CHECKED(String, y, args[1]);
7168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007169 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171 // A few fast case tests before we flatten.
7172 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007173 if (y->length() == 0) {
7174 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007176 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 return Smi::FromInt(LESS);
7178 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007179
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007180 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007181 if (d < 0) return Smi::FromInt(LESS);
7182 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183
lrn@chromium.org303ada72010-10-27 09:33:13 +00007184 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007186 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007189 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007191
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007192 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194}
7195
7196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007197RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198 NoHandleAllocation ha;
7199 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007202 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007203 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007204}
7205
7206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007207RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208 NoHandleAllocation ha;
7209 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007211
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007212 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007214}
7215
7216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007217RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218 NoHandleAllocation ha;
7219 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007220 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007222 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007223 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224}
7225
7226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227static const double kPiDividedBy4 = 0.78539816339744830962;
7228
7229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007230RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007231 NoHandleAllocation ha;
7232 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007233 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007235 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7236 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 double result;
7238 if (isinf(x) && isinf(y)) {
7239 // Make sure that the result in case of two infinite arguments
7240 // is a multiple of Pi / 4. The sign of the result is determined
7241 // by the first argument (x) and the sign of the second argument
7242 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007243 int multiplier = (x < 0) ? -1 : 1;
7244 if (y < 0) multiplier *= 3;
7245 result = multiplier * kPiDividedBy4;
7246 } else {
7247 result = atan2(x, y);
7248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007249 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007250}
7251
7252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007253RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007254 NoHandleAllocation ha;
7255 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007256 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007257
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007258 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007260}
7261
7262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007263RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 NoHandleAllocation ha;
7265 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007266 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007268 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007269 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270}
7271
7272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007273RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 NoHandleAllocation ha;
7275 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007276 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007277
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007278 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007279 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280}
7281
7282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007283RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 NoHandleAllocation ha;
7285 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007288 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290}
7291
7292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007293RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 NoHandleAllocation ha;
7295 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007298 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300}
7301
7302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007303RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304 NoHandleAllocation ha;
7305 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007308 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007309
7310 // If the second argument is a smi, it is much faster to call the
7311 // custom powi() function than the generic pow().
7312 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007313 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007314 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007315 }
7316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319}
7320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007321// Fast version of Math.pow if we know that y is not an integer and
7322// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007323RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007324 NoHandleAllocation ha;
7325 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007326 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7327 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007328 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007329 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007330 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007332 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007334 }
7335}
7336
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007338RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339 NoHandleAllocation ha;
7340 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007341 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007343 if (!args[0]->IsHeapNumber()) {
7344 // Must be smi. Return the argument unchanged for all the other types
7345 // to make fuzz-natives test happy.
7346 return args[0];
7347 }
7348
7349 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7350
7351 double value = number->value();
7352 int exponent = number->get_exponent();
7353 int sign = number->get_sign();
7354
danno@chromium.org160a7b02011-04-18 15:51:38 +00007355 if (exponent < -1) {
7356 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7357 if (sign) return isolate->heap()->minus_zero_value();
7358 return Smi::FromInt(0);
7359 }
7360
7361 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7362 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7363 // agument holds for 32-bit smis).
7364 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007365 return Smi::FromInt(static_cast<int>(value + 0.5));
7366 }
7367
7368 // If the magnitude is big enough, there's no place for fraction part. If we
7369 // try to add 0.5 to this number, 1.0 will be added instead.
7370 if (exponent >= 52) {
7371 return number;
7372 }
7373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007375
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007376 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378}
7379
7380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007381RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382 NoHandleAllocation ha;
7383 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007386 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388}
7389
7390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 NoHandleAllocation ha;
7393 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007396 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398}
7399
7400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007401RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 NoHandleAllocation ha;
7403 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007407 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408}
7409
7410
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007411static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007412 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7413 181, 212, 243, 273, 304, 334};
7414 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7415 182, 213, 244, 274, 305, 335};
7416
7417 year += month / 12;
7418 month %= 12;
7419 if (month < 0) {
7420 year--;
7421 month += 12;
7422 }
7423
7424 ASSERT(month >= 0);
7425 ASSERT(month < 12);
7426
7427 // year_delta is an arbitrary number such that:
7428 // a) year_delta = -1 (mod 400)
7429 // b) year + year_delta > 0 for years in the range defined by
7430 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7431 // Jan 1 1970. This is required so that we don't run into integer
7432 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007433 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007434 // operations.
7435 static const int year_delta = 399999;
7436 static const int base_day = 365 * (1970 + year_delta) +
7437 (1970 + year_delta) / 4 -
7438 (1970 + year_delta) / 100 +
7439 (1970 + year_delta) / 400;
7440
7441 int year1 = year + year_delta;
7442 int day_from_year = 365 * year1 +
7443 year1 / 4 -
7444 year1 / 100 +
7445 year1 / 400 -
7446 base_day;
7447
7448 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007449 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007450 }
7451
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007452 return day_from_year + day_from_month_leap[month] + day - 1;
7453}
7454
7455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 3);
7459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007460 CONVERT_SMI_ARG_CHECKED(year, 0);
7461 CONVERT_SMI_ARG_CHECKED(month, 1);
7462 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007463
7464 return Smi::FromInt(MakeDay(year, month, date));
7465}
7466
7467
7468static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7469static const int kDaysIn4Years = 4 * 365 + 1;
7470static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7471static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7472static const int kDays1970to2000 = 30 * 365 + 7;
7473static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7474 kDays1970to2000;
7475static const int kYearsOffset = 400000;
7476
7477static const char kDayInYear[] = {
7478 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7479 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7480 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7481 22, 23, 24, 25, 26, 27, 28,
7482 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7483 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7484 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7485 22, 23, 24, 25, 26, 27, 28, 29, 30,
7486 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7487 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7488 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7489 22, 23, 24, 25, 26, 27, 28, 29, 30,
7490 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7491 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7492 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7493 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7494 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7495 22, 23, 24, 25, 26, 27, 28, 29, 30,
7496 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7497 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7499 22, 23, 24, 25, 26, 27, 28, 29, 30,
7500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7501 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7502
7503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7506 22, 23, 24, 25, 26, 27, 28,
7507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7509 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7510 22, 23, 24, 25, 26, 27, 28, 29, 30,
7511 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7512 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7513 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7514 22, 23, 24, 25, 26, 27, 28, 29, 30,
7515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7516 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7517 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7518 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7519 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7520 22, 23, 24, 25, 26, 27, 28, 29, 30,
7521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7522 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7524 22, 23, 24, 25, 26, 27, 28, 29, 30,
7525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7526 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7527
7528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7531 22, 23, 24, 25, 26, 27, 28, 29,
7532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7535 22, 23, 24, 25, 26, 27, 28, 29, 30,
7536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7537 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7538 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7539 22, 23, 24, 25, 26, 27, 28, 29, 30,
7540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7541 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7543 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7545 22, 23, 24, 25, 26, 27, 28, 29, 30,
7546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7547 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7549 22, 23, 24, 25, 26, 27, 28, 29, 30,
7550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7551 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7552
7553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7556 22, 23, 24, 25, 26, 27, 28,
7557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7560 22, 23, 24, 25, 26, 27, 28, 29, 30,
7561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7562 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7563 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7564 22, 23, 24, 25, 26, 27, 28, 29, 30,
7565 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7566 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7567 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7568 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7569 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7570 22, 23, 24, 25, 26, 27, 28, 29, 30,
7571 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7572 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7573 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7574 22, 23, 24, 25, 26, 27, 28, 29, 30,
7575 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7576 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7577
7578static const char kMonthInYear[] = {
7579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7580 0, 0, 0, 0, 0, 0,
7581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7582 1, 1, 1,
7583 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7584 2, 2, 2, 2, 2, 2,
7585 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7586 3, 3, 3, 3, 3,
7587 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7588 4, 4, 4, 4, 4, 4,
7589 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7590 5, 5, 5, 5, 5,
7591 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7592 6, 6, 6, 6, 6, 6,
7593 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7594 7, 7, 7, 7, 7, 7,
7595 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7596 8, 8, 8, 8, 8,
7597 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7598 9, 9, 9, 9, 9, 9,
7599 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7600 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7601 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7602 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7603
7604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7605 0, 0, 0, 0, 0, 0,
7606 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7607 1, 1, 1,
7608 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7609 2, 2, 2, 2, 2, 2,
7610 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7611 3, 3, 3, 3, 3,
7612 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7613 4, 4, 4, 4, 4, 4,
7614 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7615 5, 5, 5, 5, 5,
7616 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7617 6, 6, 6, 6, 6, 6,
7618 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7619 7, 7, 7, 7, 7, 7,
7620 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7621 8, 8, 8, 8, 8,
7622 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7623 9, 9, 9, 9, 9, 9,
7624 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7625 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7626 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7627 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7628
7629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7630 0, 0, 0, 0, 0, 0,
7631 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7632 1, 1, 1, 1,
7633 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7634 2, 2, 2, 2, 2, 2,
7635 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7636 3, 3, 3, 3, 3,
7637 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7638 4, 4, 4, 4, 4, 4,
7639 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7640 5, 5, 5, 5, 5,
7641 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7642 6, 6, 6, 6, 6, 6,
7643 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7644 7, 7, 7, 7, 7, 7,
7645 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7646 8, 8, 8, 8, 8,
7647 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7648 9, 9, 9, 9, 9, 9,
7649 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7650 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7651 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7652 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7653
7654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7655 0, 0, 0, 0, 0, 0,
7656 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7657 1, 1, 1,
7658 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7659 2, 2, 2, 2, 2, 2,
7660 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7661 3, 3, 3, 3, 3,
7662 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7663 4, 4, 4, 4, 4, 4,
7664 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7665 5, 5, 5, 5, 5,
7666 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7667 6, 6, 6, 6, 6, 6,
7668 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7669 7, 7, 7, 7, 7, 7,
7670 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7671 8, 8, 8, 8, 8,
7672 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7673 9, 9, 9, 9, 9, 9,
7674 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7675 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7676 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7677 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7678
7679
7680// This function works for dates from 1970 to 2099.
7681static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007682 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007683#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007684 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007685#endif
7686
7687 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7688 date %= kDaysIn4Years;
7689
7690 month = kMonthInYear[date];
7691 day = kDayInYear[date];
7692
7693 ASSERT(MakeDay(year, month, day) == save_date);
7694}
7695
7696
7697static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007698 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007699#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007700 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007701#endif
7702
7703 date += kDaysOffset;
7704 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7705 date %= kDaysIn400Years;
7706
7707 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7708
7709 date--;
7710 int yd1 = date / kDaysIn100Years;
7711 date %= kDaysIn100Years;
7712 year += 100 * yd1;
7713
7714 date++;
7715 int yd2 = date / kDaysIn4Years;
7716 date %= kDaysIn4Years;
7717 year += 4 * yd2;
7718
7719 date--;
7720 int yd3 = date / 365;
7721 date %= 365;
7722 year += yd3;
7723
7724 bool is_leap = (!yd1 || yd2) && !yd3;
7725
7726 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007727 ASSERT(is_leap || (date >= 0));
7728 ASSERT((date < 365) || (is_leap && (date < 366)));
7729 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7730 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7731 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007732
7733 if (is_leap) {
7734 day = kDayInYear[2*365 + 1 + date];
7735 month = kMonthInYear[2*365 + 1 + date];
7736 } else {
7737 day = kDayInYear[date];
7738 month = kMonthInYear[date];
7739 }
7740
7741 ASSERT(MakeDay(year, month, day) == save_date);
7742}
7743
7744
7745static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007746 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007747 if (date >= 0 && date < 32 * kDaysIn4Years) {
7748 DateYMDFromTimeAfter1970(date, year, month, day);
7749 } else {
7750 DateYMDFromTimeSlow(date, year, month, day);
7751 }
7752}
7753
7754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007755RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007756 NoHandleAllocation ha;
7757 ASSERT(args.length() == 2);
7758
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007759 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007760 CONVERT_CHECKED(JSArray, res_array, args[1]);
7761
7762 int year, month, day;
7763 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007765 RUNTIME_ASSERT(res_array->elements()->map() ==
7766 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007767 FixedArray* elms = FixedArray::cast(res_array->elements());
7768 RUNTIME_ASSERT(elms->length() == 3);
7769
7770 elms->set(0, Smi::FromInt(year));
7771 elms->set(1, Smi::FromInt(month));
7772 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007774 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007775}
7776
7777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007778RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007779 HandleScope scope(isolate);
7780 ASSERT(args.length() == 3);
7781
7782 Handle<JSFunction> callee = args.at<JSFunction>(0);
7783 Object** parameters = reinterpret_cast<Object**>(args[1]);
7784 const int argument_count = Smi::cast(args[2])->value();
7785
7786 Handle<JSObject> result =
7787 isolate->factory()->NewArgumentsObject(callee, argument_count);
7788 // Allocate the elements if needed.
7789 int parameter_count = callee->shared()->formal_parameter_count();
7790 if (argument_count > 0) {
7791 if (parameter_count > 0) {
7792 int mapped_count = Min(argument_count, parameter_count);
7793 Handle<FixedArray> parameter_map =
7794 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7795 parameter_map->set_map(
7796 isolate->heap()->non_strict_arguments_elements_map());
7797
7798 Handle<Map> old_map(result->map());
7799 Handle<Map> new_map =
7800 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007801 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007802
7803 result->set_map(*new_map);
7804 result->set_elements(*parameter_map);
7805
7806 // Store the context and the arguments array at the beginning of the
7807 // parameter map.
7808 Handle<Context> context(isolate->context());
7809 Handle<FixedArray> arguments =
7810 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7811 parameter_map->set(0, *context);
7812 parameter_map->set(1, *arguments);
7813
7814 // Loop over the actual parameters backwards.
7815 int index = argument_count - 1;
7816 while (index >= mapped_count) {
7817 // These go directly in the arguments array and have no
7818 // corresponding slot in the parameter map.
7819 arguments->set(index, *(parameters - index - 1));
7820 --index;
7821 }
7822
7823 ScopeInfo<> scope_info(callee->shared()->scope_info());
7824 while (index >= 0) {
7825 // Detect duplicate names to the right in the parameter list.
7826 Handle<String> name = scope_info.parameter_name(index);
7827 int context_slot_count = scope_info.number_of_context_slots();
7828 bool duplicate = false;
7829 for (int j = index + 1; j < parameter_count; ++j) {
7830 if (scope_info.parameter_name(j).is_identical_to(name)) {
7831 duplicate = true;
7832 break;
7833 }
7834 }
7835
7836 if (duplicate) {
7837 // This goes directly in the arguments array with a hole in the
7838 // parameter map.
7839 arguments->set(index, *(parameters - index - 1));
7840 parameter_map->set_the_hole(index + 2);
7841 } else {
7842 // The context index goes in the parameter map with a hole in the
7843 // arguments array.
7844 int context_index = -1;
7845 for (int j = Context::MIN_CONTEXT_SLOTS;
7846 j < context_slot_count;
7847 ++j) {
7848 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7849 context_index = j;
7850 break;
7851 }
7852 }
7853 ASSERT(context_index >= 0);
7854 arguments->set_the_hole(index);
7855 parameter_map->set(index + 2, Smi::FromInt(context_index));
7856 }
7857
7858 --index;
7859 }
7860 } else {
7861 // If there is no aliasing, the arguments object elements are not
7862 // special in any way.
7863 Handle<FixedArray> elements =
7864 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7865 result->set_elements(*elements);
7866 for (int i = 0; i < argument_count; ++i) {
7867 elements->set(i, *(parameters - i - 1));
7868 }
7869 }
7870 }
7871 return *result;
7872}
7873
7874
7875RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007876 NoHandleAllocation ha;
7877 ASSERT(args.length() == 3);
7878
7879 JSFunction* callee = JSFunction::cast(args[0]);
7880 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007881 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007882
lrn@chromium.org303ada72010-10-27 09:33:13 +00007883 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 { MaybeObject* maybe_result =
7885 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886 if (!maybe_result->ToObject(&result)) return maybe_result;
7887 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007888 // Allocate the elements if needed.
7889 if (length > 0) {
7890 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007891 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007893 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7894 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007895
7896 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007897 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007899 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007900
7901 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007902 for (int i = 0; i < length; i++) {
7903 array->set(i, *--parameters, mode);
7904 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007905 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007906 }
7907 return result;
7908}
7909
7910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007913 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007914 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007915 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007916 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917
whesse@chromium.org7b260152011-06-20 15:33:18 +00007918 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007919 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007920 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007922 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7923 context,
7924 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007925 return *result;
7926}
7927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007928
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007929static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
7930 int bound_argc,
7931 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932 // Find frame containing arguments passed to the caller.
7933 JavaScriptFrameIterator it;
7934 JavaScriptFrame* frame = it.frame();
7935 List<JSFunction*> functions(2);
7936 frame->GetFunctions(&functions);
7937 if (functions.length() > 1) {
7938 int inlined_frame_index = functions.length() - 1;
7939 JSFunction* inlined_function = functions[inlined_frame_index];
7940 int args_count = inlined_function->shared()->formal_parameter_count();
7941 ScopedVector<SlotRef> args_slots(args_count);
7942 SlotRef::ComputeSlotMappingForArguments(frame,
7943 inlined_frame_index,
7944 &args_slots);
7945
7946 *total_argc = bound_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007947 SmartArrayPointer<Handle<Object> > param_data(
7948 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007949 for (int i = 0; i < args_count; i++) {
7950 Handle<Object> val = args_slots[i].GetValue();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007951 param_data[bound_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952 }
7953 return param_data;
7954 } else {
7955 it.AdvanceToArgumentsFrame();
7956 frame = it.frame();
7957 int args_count = frame->ComputeParametersCount();
7958
7959 *total_argc = bound_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007960 SmartArrayPointer<Handle<Object> > param_data(
7961 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007962 for (int i = 0; i < args_count; i++) {
7963 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007964 param_data[bound_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007965 }
7966 return param_data;
7967 }
7968}
7969
7970
7971RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007973 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007974 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007975 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007976
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007977 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007978 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007979 int bound_argc = 0;
7980 if (!args[1]->IsNull()) {
7981 CONVERT_ARG_CHECKED(JSArray, params, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007982 RUNTIME_ASSERT(params->HasFastTypeElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007983 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007984 bound_argc = Smi::cast(params->length())->value();
7985 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007987 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007988 SmartArrayPointer<Handle<Object> > param_data =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007989 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007990 for (int i = 0; i < bound_argc; i++) {
7991 Handle<Object> val = Handle<Object>(bound_args->get(i));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007992 param_data[i] = val;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007993 }
7994
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007995 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007996 Handle<Object> result =
7997 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007998 if (exception) {
7999 return Failure::Exception();
8000 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008001
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008002 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008003 return *result;
8004}
8005
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007static void TrySettingInlineConstructStub(Isolate* isolate,
8008 Handle<JSFunction> function) {
8009 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008010 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008012 }
8013 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008014 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008015 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008016 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008017 function->shared()->set_construct_stub(
8018 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008019 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008020 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008021}
8022
8023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008024RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008026 ASSERT(args.length() == 1);
8027
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008028 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008030 // If the constructor isn't a proper function we throw a type error.
8031 if (!constructor->IsJSFunction()) {
8032 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8033 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 isolate->factory()->NewTypeError("not_constructor", arguments);
8035 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008036 }
8037
8038 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008039
8040 // If function should not have prototype, construction is not allowed. In this
8041 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008042 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008043 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8044 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008045 isolate->factory()->NewTypeError("not_constructor", arguments);
8046 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008047 }
8048
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008049#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008050 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008051 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008052 if (debug->StepInActive()) {
8053 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008054 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008055#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008057 if (function->has_initial_map()) {
8058 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059 // The 'Function' function ignores the receiver object when
8060 // called using 'new' and creates a new JSFunction object that
8061 // is returned. The receiver object is only used for error
8062 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008063 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008064 // allocate JSFunctions since it does not properly initialize
8065 // the shared part of the function. Since the receiver is
8066 // ignored anyway, we use the global object as the receiver
8067 // instead of a new JSFunction object. This way, errors are
8068 // reported the same way whether or not 'Function' is called
8069 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 }
8073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008074 // The function should be compiled for the optimization hints to be
8075 // available. We cannot use EnsureCompiled because that forces a
8076 // compilation through the shared function info which makes it
8077 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008078 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008079 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008080
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008081 if (!function->has_initial_map() &&
8082 shared->IsInobjectSlackTrackingInProgress()) {
8083 // The tracking is already in progress for another function. We can only
8084 // track one initial_map at a time, so we force the completion before the
8085 // function is called as a constructor for the first time.
8086 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008087 }
8088
8089 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8091 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008092 // Delay setting the stub if inobject slack tracking is in progress.
8093 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008095 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 isolate->counters()->constructed_objects()->Increment();
8098 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008099
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008100 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101}
8102
8103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008104RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008105 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008106 ASSERT(args.length() == 1);
8107
8108 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8109 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008110 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008112 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008113}
8114
8115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008116RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008118 ASSERT(args.length() == 1);
8119
8120 Handle<JSFunction> function = args.at<JSFunction>(0);
8121#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008122 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008123 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008124 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008125 PrintF("]\n");
8126 }
8127#endif
8128
lrn@chromium.org34e60782011-09-15 07:25:40 +00008129 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008130 ASSERT(!function->is_compiled());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008131 if (!CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008132 return Failure::Exception();
8133 }
8134
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008135 // All done. Return the compiled code.
8136 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008137 return function->code();
8138}
8139
8140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008141RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008142 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008143 ASSERT(args.length() == 1);
8144 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008145
8146 // If the function is not compiled ignore the lazy
8147 // recompilation. This can happen if the debugger is activated and
8148 // the function is returned to the not compiled state.
8149 if (!function->shared()->is_compiled()) {
8150 function->ReplaceCode(function->shared()->code());
8151 return function->code();
8152 }
8153
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154 // If the function is not optimizable or debugger is active continue using the
8155 // code from the full compiler.
8156 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008157 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008158 if (FLAG_trace_opt) {
8159 PrintF("[failed to optimize ");
8160 function->PrintName();
8161 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8162 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008163 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008164 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008165 function->ReplaceCode(function->shared()->code());
8166 return function->code();
8167 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008168 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008169 return function->code();
8170 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008171 if (FLAG_trace_opt) {
8172 PrintF("[failed to optimize ");
8173 function->PrintName();
8174 PrintF(": optimized compilation failed]\n");
8175 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008176 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008177 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008178}
8179
8180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008181RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008182 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183 ASSERT(args.length() == 1);
8184 RUNTIME_ASSERT(args[0]->IsSmi());
8185 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008186 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008187 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8188 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008189 int frames = deoptimizer->output_count();
8190
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008191 deoptimizer->MaterializeHeapNumbers();
8192 delete deoptimizer;
8193
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008194 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008195 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008196 for (int i = 0; i < frames - 1; i++) it.Advance();
8197 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008198
8199 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008201 Handle<Object> arguments;
8202 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204 if (arguments.is_null()) {
8205 // FunctionGetArguments can't throw an exception, so cast away the
8206 // doubt with an assert.
8207 arguments = Handle<Object>(
8208 Accessors::FunctionGetArguments(*function,
8209 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 ASSERT(*arguments != isolate->heap()->null_value());
8211 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008212 }
8213 frame->SetExpression(i, *arguments);
8214 }
8215 }
8216
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217 if (type == Deoptimizer::EAGER) {
8218 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008219 }
8220
8221 // Avoid doing too much work when running with --always-opt and keep
8222 // the optimized code around.
8223 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008224 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008225 }
8226
8227 // Count the number of optimized activations of the function.
8228 int activations = 0;
8229 while (!it.done()) {
8230 JavaScriptFrame* frame = it.frame();
8231 if (frame->is_optimized() && frame->function() == *function) {
8232 activations++;
8233 }
8234 it.Advance();
8235 }
8236
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008237 if (activations == 0) {
8238 if (FLAG_trace_deopt) {
8239 PrintF("[removing optimized code for: ");
8240 function->PrintName();
8241 PrintF("]\n");
8242 }
8243 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008244 } else {
8245 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008246 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008247 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008248}
8249
8250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008251RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008252 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008253 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008255}
8256
8257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008258RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008260 ASSERT(args.length() == 1);
8261 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008263
8264 Deoptimizer::DeoptimizeFunction(*function);
8265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008267}
8268
8269
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008270RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8271#if defined(USE_SIMULATOR)
8272 return isolate->heap()->true_value();
8273#else
8274 return isolate->heap()->false_value();
8275#endif
8276}
8277
8278
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008279RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8280 HandleScope scope(isolate);
8281 ASSERT(args.length() == 1);
8282 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8283 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8284 function->MarkForLazyRecompilation();
8285 return isolate->heap()->undefined_value();
8286}
8287
8288
lrn@chromium.org1c092762011-05-09 09:42:16 +00008289RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8290 HandleScope scope(isolate);
8291 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008292 // The least significant bit (after untagging) indicates whether the
8293 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008294 if (!V8::UseCrankshaft()) {
8295 return Smi::FromInt(4); // 4 == "never".
8296 }
8297 if (FLAG_always_opt) {
8298 return Smi::FromInt(3); // 3 == "always".
8299 }
8300 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8301 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8302 : Smi::FromInt(2); // 2 == "no".
8303}
8304
8305
8306RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8307 HandleScope scope(isolate);
8308 ASSERT(args.length() == 1);
8309 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8310 return Smi::FromInt(function->shared()->opt_count());
8311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008316 ASSERT(args.length() == 1);
8317 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8318
8319 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008320 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008321
8322 // We have hit a back edge in an unoptimized frame for a function that was
8323 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008325 // Keep track of whether we've succeeded in optimizing.
8326 bool succeeded = unoptimized->optimizable();
8327 if (succeeded) {
8328 // If we are trying to do OSR when there are already optimized
8329 // activations of the function, it means (a) the function is directly or
8330 // indirectly recursive and (b) an optimized invocation has been
8331 // deoptimized so that we are currently in an unoptimized activation.
8332 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008333 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008334 while (succeeded && !it.done()) {
8335 JavaScriptFrame* frame = it.frame();
8336 succeeded = !frame->is_optimized() || frame->function() != *function;
8337 it.Advance();
8338 }
8339 }
8340
8341 int ast_id = AstNode::kNoNumber;
8342 if (succeeded) {
8343 // The top JS function is this one, the PC is somewhere in the
8344 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008345 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008346 JavaScriptFrame* frame = it.frame();
8347 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008348 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008349 ASSERT(unoptimized->contains(frame->pc()));
8350
8351 // Use linear search of the unoptimized code's stack check table to find
8352 // the AST id matching the PC.
8353 Address start = unoptimized->instruction_start();
8354 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008355 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008356 uint32_t table_length = Memory::uint32_at(table_cursor);
8357 table_cursor += kIntSize;
8358 for (unsigned i = 0; i < table_length; ++i) {
8359 // Table entries are (AST id, pc offset) pairs.
8360 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8361 if (pc_offset == target_pc_offset) {
8362 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8363 break;
8364 }
8365 table_cursor += 2 * kIntSize;
8366 }
8367 ASSERT(ast_id != AstNode::kNoNumber);
8368 if (FLAG_trace_osr) {
8369 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8370 function->PrintName();
8371 PrintF("]\n");
8372 }
8373
8374 // Try to compile the optimized code. A true return value from
8375 // CompileOptimized means that compilation succeeded, not necessarily
8376 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008377 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8378 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008379 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8380 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008381 if (data->OsrPcOffset()->value() >= 0) {
8382 if (FLAG_trace_osr) {
8383 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008384 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008385 }
8386 ASSERT(data->OsrAstId()->value() == ast_id);
8387 } else {
8388 // We may never generate the desired OSR entry if we emit an
8389 // early deoptimize.
8390 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008391 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008392 } else {
8393 succeeded = false;
8394 }
8395 }
8396
8397 // Revert to the original stack checks in the original unoptimized code.
8398 if (FLAG_trace_osr) {
8399 PrintF("[restoring original stack checks in ");
8400 function->PrintName();
8401 PrintF("]\n");
8402 }
8403 StackCheckStub check_stub;
8404 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008405 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008406 Deoptimizer::RevertStackCheckCode(*unoptimized,
8407 *check_code,
8408 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008409
8410 // Allow OSR only at nesting level zero again.
8411 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8412
8413 // If the optimization attempt succeeded, return the AST id tagged as a
8414 // smi. This tells the builtin that we need to translate the unoptimized
8415 // frame to an optimized one.
8416 if (succeeded) {
8417 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8418 return Smi::FromInt(ast_id);
8419 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008420 if (function->IsMarkedForLazyRecompilation()) {
8421 function->ReplaceCode(function->shared()->code());
8422 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 return Smi::FromInt(-1);
8424 }
8425}
8426
8427
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008428RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8429 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8430 return isolate->heap()->undefined_value();
8431}
8432
8433
lrn@chromium.org34e60782011-09-15 07:25:40 +00008434RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8435 HandleScope scope(isolate);
8436 ASSERT(args.length() == 5);
8437 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8438 Object* receiver = args[1];
8439 CONVERT_CHECKED(JSObject, arguments, args[2]);
8440 CONVERT_CHECKED(Smi, shift, args[3]);
8441 CONVERT_CHECKED(Smi, arity, args[4]);
8442
8443 int offset = shift->value();
8444 int argc = arity->value();
8445 ASSERT(offset >= 0);
8446 ASSERT(argc >= 0);
8447
8448 // If there are too many arguments, allocate argv via malloc.
8449 const int argv_small_size = 10;
8450 Handle<Object> argv_small_buffer[argv_small_size];
8451 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8452 Handle<Object>* argv = argv_small_buffer;
8453 if (argc > argv_small_size) {
8454 argv = new Handle<Object>[argc];
8455 if (argv == NULL) return isolate->StackOverflow();
8456 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8457 }
8458
8459 for (int i = 0; i < argc; ++i) {
8460 MaybeObject* maybe = arguments->GetElement(offset + i);
8461 Object* object;
8462 if (!maybe->To<Object>(&object)) return maybe;
8463 argv[i] = Handle<Object>(object);
8464 }
8465
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008466 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008467 Handle<JSReceiver> hfun(fun);
8468 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008469 Handle<Object> result =
8470 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008471
8472 if (threw) return Failure::Exception();
8473 return *result;
8474}
8475
8476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008477RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008479 ASSERT(args.length() == 1);
8480 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8481 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8482}
8483
8484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008485RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008486 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008487 ASSERT(args.length() == 1);
8488 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8489 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8490}
8491
8492
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008493RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008494 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008495 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496
kasper.lund7276f142008-07-30 08:49:36 +00008497 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008498 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008499 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 { MaybeObject* maybe_result =
8501 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008502 if (!maybe_result->ToObject(&result)) return maybe_result;
8503 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008505 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008506
kasper.lund7276f142008-07-30 08:49:36 +00008507 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508}
8509
lrn@chromium.org303ada72010-10-27 09:33:13 +00008510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008511RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8512 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008513 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008514 JSObject* extension_object;
8515 if (args[0]->IsJSObject()) {
8516 extension_object = JSObject::cast(args[0]);
8517 } else {
8518 // Convert the object to a proper JavaScript object.
8519 MaybeObject* maybe_js_object = args[0]->ToObject();
8520 if (!maybe_js_object->To(&extension_object)) {
8521 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8522 HandleScope scope(isolate);
8523 Handle<Object> handle = args.at<Object>(0);
8524 Handle<Object> result =
8525 isolate->factory()->NewTypeError("with_expression",
8526 HandleVector(&handle, 1));
8527 return isolate->Throw(*result);
8528 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008529 return maybe_js_object;
8530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008531 }
8532 }
8533
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008534 JSFunction* function;
8535 if (args[1]->IsSmi()) {
8536 // A smi sentinel indicates a context nested inside global code rather
8537 // than some function. There is a canonical empty function that can be
8538 // gotten from the global context.
8539 function = isolate->context()->global_context()->closure();
8540 } else {
8541 function = JSFunction::cast(args[1]);
8542 }
8543
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008544 Context* context;
8545 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008546 isolate->heap()->AllocateWithContext(function,
8547 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008548 extension_object);
8549 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008550 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008551 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008552}
8553
8554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008555RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008556 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008557 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008558 String* name = String::cast(args[0]);
8559 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008560 JSFunction* function;
8561 if (args[2]->IsSmi()) {
8562 // A smi sentinel indicates a context nested inside global code rather
8563 // than some function. There is a canonical empty function that can be
8564 // gotten from the global context.
8565 function = isolate->context()->global_context()->closure();
8566 } else {
8567 function = JSFunction::cast(args[2]);
8568 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008569 Context* context;
8570 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008571 isolate->heap()->AllocateCatchContext(function,
8572 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008573 name,
8574 thrown_object);
8575 if (!maybe_context->To(&context)) return maybe_context;
8576 isolate->set_context(context);
8577 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008578}
8579
8580
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008581RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8582 NoHandleAllocation ha;
8583 ASSERT(args.length() == 2);
8584 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8585 JSFunction* function;
8586 if (args[1]->IsSmi()) {
8587 // A smi sentinel indicates a context nested inside global code rather
8588 // than some function. There is a canonical empty function that can be
8589 // gotten from the global context.
8590 function = isolate->context()->global_context()->closure();
8591 } else {
8592 function = JSFunction::cast(args[1]);
8593 }
8594 Context* context;
8595 MaybeObject* maybe_context =
8596 isolate->heap()->AllocateBlockContext(function,
8597 isolate->context(),
8598 scope_info);
8599 if (!maybe_context->To(&context)) return maybe_context;
8600 isolate->set_context(context);
8601 return context;
8602}
8603
8604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008605RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 ASSERT(args.length() == 2);
8608
8609 CONVERT_ARG_CHECKED(Context, context, 0);
8610 CONVERT_ARG_CHECKED(String, name, 1);
8611
8612 int index;
8613 PropertyAttributes attributes;
8614 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008615 BindingFlags binding_flags;
8616 Handle<Object> holder = context->Lookup(name,
8617 flags,
8618 &index,
8619 &attributes,
8620 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008622 // If the slot was not found the result is true.
8623 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008624 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008625 }
8626
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008627 // If the slot was found in a context, it should be DONT_DELETE.
8628 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008629 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008630 }
8631
8632 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008633 // the global object, or the subject of a with. Try to delete it
8634 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008635 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008636 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637}
8638
8639
ager@chromium.orga1645e22009-09-09 19:27:10 +00008640// A mechanism to return a pair of Object pointers in registers (if possible).
8641// How this is achieved is calling convention-dependent.
8642// All currently supported x86 compiles uses calling conventions that are cdecl
8643// variants where a 64-bit value is returned in two 32-bit registers
8644// (edx:eax on ia32, r1:r0 on ARM).
8645// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8646// In Win64 calling convention, a struct of two pointers is returned in memory,
8647// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008648#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008649struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008650 MaybeObject* x;
8651 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008652};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008653
lrn@chromium.org303ada72010-10-27 09:33:13 +00008654static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008655 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008656 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8657 // In Win64 they are assigned to a hidden first argument.
8658 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008659}
8660#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008661typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008662static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008664 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008666#endif
8667
8668
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008669static inline MaybeObject* Unhole(Heap* heap,
8670 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008671 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8673 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008674 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675}
8676
8677
danno@chromium.org40cb8782011-05-25 07:58:50 +00008678static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8679 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008680 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008682 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008683 JSFunction* context_extension_function =
8684 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008685 // If the holder isn't a context extension object, we just return it
8686 // as the receiver. This allows arguments objects to be used as
8687 // receivers, but only if they are put in the context scope chain
8688 // explicitly via a with-statement.
8689 Object* constructor = holder->map()->constructor();
8690 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008691 // Fall back to using the global object as the implicit receiver if
8692 // the property turns out to be a local variable allocated in a
8693 // context extension object - introduced via eval. Implicit global
8694 // receivers are indicated with the hole value.
8695 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008696}
8697
8698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699static ObjectPair LoadContextSlotHelper(Arguments args,
8700 Isolate* isolate,
8701 bool throw_error) {
8702 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008703 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008704
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008705 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008707 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008709 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008710
8711 int index;
8712 PropertyAttributes attributes;
8713 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008714 BindingFlags binding_flags;
8715 Handle<Object> holder = context->Lookup(name,
8716 flags,
8717 &index,
8718 &attributes,
8719 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008720
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008721 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008722 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008723 ASSERT(holder->IsContext());
8724 // If the "property" we were looking for is a local variable, the
8725 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008726 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008727 // Use the hole as the receiver to signal that the receiver is implicit
8728 // and that the global receiver should be used (as distinguished from an
8729 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008730 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008731 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008732 // Check for uninitialized bindings.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008733 if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008734 Handle<Object> reference_error =
8735 isolate->factory()->NewReferenceError("not_defined",
8736 HandleVector(&name, 1));
8737 return MakePair(isolate->Throw(*reference_error), NULL);
8738 } else {
8739 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8740 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008741 }
8742
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008743 // Otherwise, if the slot was found the holder is a context extension
8744 // object, subject of a with, or a global object. We read the named
8745 // property from it.
8746 if (!holder.is_null()) {
8747 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8748 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008749 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008750 Handle<Object> receiver_handle(object->IsGlobalObject()
8751 ? GlobalObject::cast(*object)->global_receiver()
8752 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008753
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008754 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008755 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008756 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008757 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758 }
8759
8760 if (throw_error) {
8761 // The property doesn't exist - throw exception.
8762 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 isolate->factory()->NewReferenceError("not_defined",
8764 HandleVector(&name, 1));
8765 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008766 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008767 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 return MakePair(isolate->heap()->undefined_value(),
8769 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008770 }
8771}
8772
8773
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008774RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008775 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776}
8777
8778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008779RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781}
8782
8783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008784RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008786 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008788 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008790 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008791 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008792 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8793 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008794 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795
8796 int index;
8797 PropertyAttributes attributes;
8798 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008799 BindingFlags binding_flags;
8800 Handle<Object> holder = context->Lookup(name,
8801 flags,
8802 &index,
8803 &attributes,
8804 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805
8806 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008807 // The property was found in a context slot.
8808 Handle<Context> context = Handle<Context>::cast(holder);
8809 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8810 context->get(index)->IsTheHole()) {
8811 Handle<Object> error =
8812 isolate->factory()->NewReferenceError("not_defined",
8813 HandleVector(&name, 1));
8814 return isolate->Throw(*error);
8815 }
8816 // Ignore if read_only variable.
8817 if ((attributes & READ_ONLY) == 0) {
8818 // Context is a fixed array and set cannot fail.
8819 context->set(index, *value);
8820 } else if (strict_mode == kStrictMode) {
8821 // Setting read only property in strict mode.
8822 Handle<Object> error =
8823 isolate->factory()->NewTypeError("strict_cannot_assign",
8824 HandleVector(&name, 1));
8825 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008826 }
8827 return *value;
8828 }
8829
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008830 // Slow case: The property is not in a context slot. It is either in a
8831 // context extension object, a property of the subject of a with, or a
8832 // property of the global object.
8833 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008834
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008835 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008836 // The property exists on the holder.
8837 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008838 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008839 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008841
8842 if (strict_mode == kStrictMode) {
8843 // Throw in strict mode (assignment to undefined variable).
8844 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008845 isolate->factory()->NewReferenceError(
8846 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008847 return isolate->Throw(*error);
8848 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008849 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008850 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008851 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852 }
8853
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008854 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008855 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008856 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008857 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008859 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008860 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008861 // Setting read only property in strict mode.
8862 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008863 isolate->factory()->NewTypeError(
8864 "strict_cannot_assign", HandleVector(&name, 1));
8865 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 }
8867 return *value;
8868}
8869
8870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008871RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 ASSERT(args.length() == 1);
8874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876}
8877
8878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008879RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008880 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008881 ASSERT(args.length() == 1);
8882
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884}
8885
8886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008887RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008888 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008890}
8891
8892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008893RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895 ASSERT(args.length() == 1);
8896
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 isolate->factory()->NewReferenceError("not_defined",
8900 HandleVector(&name, 1));
8901 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902}
8903
8904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008905RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008906 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907
8908 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008909 if (isolate->stack_guard()->IsStackOverflow()) {
8910 NoHandleAllocation na;
8911 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008913
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008914 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915}
8916
8917
8918// NOTE: These PrintXXX functions are defined for all builds (not just
8919// DEBUG builds) because we may want to be able to trace function
8920// calls in all modes.
8921static void PrintString(String* str) {
8922 // not uncommon to have empty strings
8923 if (str->length() > 0) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008924 SmartArrayPointer<char> s =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8926 PrintF("%s", *s);
8927 }
8928}
8929
8930
8931static void PrintObject(Object* obj) {
8932 if (obj->IsSmi()) {
8933 PrintF("%d", Smi::cast(obj)->value());
8934 } else if (obj->IsString() || obj->IsSymbol()) {
8935 PrintString(String::cast(obj));
8936 } else if (obj->IsNumber()) {
8937 PrintF("%g", obj->Number());
8938 } else if (obj->IsFailure()) {
8939 PrintF("<failure>");
8940 } else if (obj->IsUndefined()) {
8941 PrintF("<undefined>");
8942 } else if (obj->IsNull()) {
8943 PrintF("<null>");
8944 } else if (obj->IsTrue()) {
8945 PrintF("<true>");
8946 } else if (obj->IsFalse()) {
8947 PrintF("<false>");
8948 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008949 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 }
8951}
8952
8953
8954static int StackSize() {
8955 int n = 0;
8956 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8957 return n;
8958}
8959
8960
8961static void PrintTransition(Object* result) {
8962 // indentation
8963 { const int nmax = 80;
8964 int n = StackSize();
8965 if (n <= nmax)
8966 PrintF("%4d:%*s", n, n, "");
8967 else
8968 PrintF("%4d:%*s", n, nmax, "...");
8969 }
8970
8971 if (result == NULL) {
8972 // constructor calls
8973 JavaScriptFrameIterator it;
8974 JavaScriptFrame* frame = it.frame();
8975 if (frame->IsConstructor()) PrintF("new ");
8976 // function name
8977 Object* fun = frame->function();
8978 if (fun->IsJSFunction()) {
8979 PrintObject(JSFunction::cast(fun)->shared()->name());
8980 } else {
8981 PrintObject(fun);
8982 }
8983 // function arguments
8984 // (we are intentionally only printing the actually
8985 // supplied parameters, not all parameters required)
8986 PrintF("(this=");
8987 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008988 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989 for (int i = 0; i < length; i++) {
8990 PrintF(", ");
8991 PrintObject(frame->GetParameter(i));
8992 }
8993 PrintF(") {\n");
8994
8995 } else {
8996 // function result
8997 PrintF("} -> ");
8998 PrintObject(result);
8999 PrintF("\n");
9000 }
9001}
9002
9003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009004RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009005 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006 NoHandleAllocation ha;
9007 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009}
9010
9011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009012RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013 NoHandleAllocation ha;
9014 PrintTransition(args[0]);
9015 return args[0]; // return TOS
9016}
9017
9018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009019RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020 NoHandleAllocation ha;
9021 ASSERT(args.length() == 1);
9022
9023#ifdef DEBUG
9024 if (args[0]->IsString()) {
9025 // If we have a string, assume it's a code "marker"
9026 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009027 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009029 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9030 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 } else {
9032 PrintF("DebugPrint: ");
9033 }
9034 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009035 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009036 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009037 HeapObject::cast(args[0])->map()->Print();
9038 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009040 // ShortPrint is available in release mode. Print is not.
9041 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009042#endif
9043 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009044 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045
9046 return args[0]; // return TOS
9047}
9048
9049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009050RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009051 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 isolate->PrintStack();
9054 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009055}
9056
9057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009058RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009060 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061
9062 // According to ECMA-262, section 15.9.1, page 117, the precision of
9063 // the number in a Date object representing a particular instant in
9064 // time is milliseconds. Therefore, we floor the result of getting
9065 // the OS time.
9066 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068}
9069
9070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009071RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009072 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009073 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009075 CONVERT_ARG_CHECKED(String, str, 0);
9076 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009078 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009079
9080 MaybeObject* maybe_result_array =
9081 output->EnsureCanContainNonSmiElements();
9082 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009083 RUNTIME_ASSERT(output->HasFastElements());
9084
9085 AssertNoAllocation no_allocation;
9086
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009087 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009088 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9089 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009090 String::FlatContent str_content = str->GetFlatContent();
9091 if (str_content.IsAscii()) {
9092 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009093 output_array,
9094 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009095 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009096 ASSERT(str_content.IsTwoByte());
9097 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009098 output_array,
9099 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009100 }
9101
9102 if (result) {
9103 return *output;
9104 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 }
9107}
9108
9109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009110RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 NoHandleAllocation ha;
9112 ASSERT(args.length() == 1);
9113
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009114 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009115 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117}
9118
9119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009120RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009122 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009125}
9126
9127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009128RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 NoHandleAllocation ha;
9130 ASSERT(args.length() == 1);
9131
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009132 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009134}
9135
9136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009137RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009138 ASSERT(args.length() == 1);
9139 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009141 return JSGlobalObject::cast(global)->global_receiver();
9142}
9143
9144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009145RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009147 ASSERT_EQ(1, args.length());
9148 CONVERT_ARG_CHECKED(String, source, 0);
9149
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009150 source = Handle<String>(source->TryFlattenGetString());
9151 // Optimized fast case where we only have ascii characters.
9152 Handle<Object> result;
9153 if (source->IsSeqAsciiString()) {
9154 result = JsonParser<true>::Parse(source);
9155 } else {
9156 result = JsonParser<false>::Parse(source);
9157 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009158 if (result.is_null()) {
9159 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009161 return Failure::Exception();
9162 }
9163 return *result;
9164}
9165
9166
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009167bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9168 Handle<Context> context) {
9169 if (context->allow_code_gen_from_strings()->IsFalse()) {
9170 // Check with callback if set.
9171 AllowCodeGenerationFromStringsCallback callback =
9172 isolate->allow_code_gen_callback();
9173 if (callback == NULL) {
9174 // No callback set and code generation disallowed.
9175 return false;
9176 } else {
9177 // Callback set. Let it decide if code generation is allowed.
9178 VMState state(isolate, EXTERNAL);
9179 return callback(v8::Utils::ToLocal(context));
9180 }
9181 }
9182 return true;
9183}
9184
9185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009186RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009188 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009189 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009190
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009191 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009193
9194 // Check if global context allows code generation from
9195 // strings. Throw an exception if it doesn't.
9196 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9197 return isolate->Throw(*isolate->factory()->NewError(
9198 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9199 }
9200
9201 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009202 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9203 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009204 true,
9205 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009206 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9209 context,
9210 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009211 return *fun;
9212}
9213
9214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215static ObjectPair CompileGlobalEval(Isolate* isolate,
9216 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009217 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009218 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009219 Handle<Context> context = Handle<Context>(isolate->context());
9220 Handle<Context> global_context = Handle<Context>(context->global_context());
9221
9222 // Check if global context allows code generation from
9223 // strings. Throw an exception if it doesn't.
9224 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9225 isolate->Throw(*isolate->factory()->NewError(
9226 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9227 return MakePair(Failure::Exception(), NULL);
9228 }
9229
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009230 // Deal with a normal eval call with a string argument. Compile it
9231 // and return the compiled function bound in the local context.
9232 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9233 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009235 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009236 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009237 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009238 Handle<JSFunction> compiled =
9239 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009240 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009241 return MakePair(*compiled, *receiver);
9242}
9243
9244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009245RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009246 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009247
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009249 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009250 Handle<Object> receiver; // Will be overwritten.
9251
9252 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009253 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009254#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009256 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009257 StackFrameLocator locator;
9258 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009259 ASSERT(Context::cast(frame->context()) == *context);
9260#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009261
9262 // Find where the 'eval' symbol is bound. It is unaliased only if
9263 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009264 int index = -1;
9265 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009266 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009267 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009268 // Don't follow context chains in Context::Lookup and implement the loop
9269 // up the context chain here, so that we can know the context where eval
9270 // was found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009271 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9272 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009273 &index,
9274 &attributes,
9275 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009276 // Stop search when eval is found or when the global context is
9277 // reached.
9278 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009279 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009280 }
9281
iposva@chromium.org245aa852009-02-10 00:49:54 +00009282 // If eval could not be resolved, it has been deleted and we need to
9283 // throw a reference error.
9284 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009285 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009286 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009287 isolate->factory()->NewReferenceError("not_defined",
9288 HandleVector(&name, 1));
9289 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009290 }
9291
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009292 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009293 // 'eval' is not bound in the global context. Just call the function
9294 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009295 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009296 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009297 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009298 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009299 }
9300
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009301 // 'eval' is bound in the global context, but it may have been overwritten.
9302 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009304 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009305 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009306 }
9307
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009308 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009309 return CompileGlobalEval(isolate,
9310 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009311 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009312 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009313}
9314
9315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009316RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009317 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009319 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009320 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009321
9322 // 'eval' is bound in the global context, but it may have been overwritten.
9323 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009325 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009326 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009327 }
9328
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009329 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009330 return CompileGlobalEval(isolate,
9331 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009332 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009333 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009334}
9335
9336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009337RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338 // This utility adjusts the property attributes for newly created Function
9339 // object ("new Function(...)") by changing the map.
9340 // All it does is changing the prototype property to enumerable
9341 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009343 ASSERT(args.length() == 1);
9344 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345
9346 Handle<Map> map = func->shared()->strict_mode()
9347 ? isolate->strict_mode_function_instance_map()
9348 : isolate->function_instance_map();
9349
9350 ASSERT(func->map()->instance_type() == map->instance_type());
9351 ASSERT(func->map()->instance_size() == map->instance_size());
9352 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 return *func;
9354}
9355
9356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009357RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009358 // Allocate a block of memory in NewSpace (filled with a filler).
9359 // Use as fallback for allocation in generated code when NewSpace
9360 // is full.
9361 ASSERT(args.length() == 1);
9362 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9363 int size = size_smi->value();
9364 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9365 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 Heap* heap = isolate->heap();
9367 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009368 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009369 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009371 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009373 }
9374 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009375 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009376}
9377
9378
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009379// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009380// array. Returns true if the element was pushed on the stack and
9381// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009382RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009383 ASSERT(args.length() == 2);
9384 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009385 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009386 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009387 int length = Smi::cast(array->length())->value();
9388 FixedArray* elements = FixedArray::cast(array->elements());
9389 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009391 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009392 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009393 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009394 { MaybeObject* maybe_obj =
9395 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009396 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9397 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009399}
9400
9401
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009402/**
9403 * A simple visitor visits every element of Array's.
9404 * The backend storage can be a fixed array for fast elements case,
9405 * or a dictionary for sparse array. Since Dictionary is a subtype
9406 * of FixedArray, the class can be used by both fast and slow cases.
9407 * The second parameter of the constructor, fast_elements, specifies
9408 * whether the storage is a FixedArray or Dictionary.
9409 *
9410 * An index limit is used to deal with the situation that a result array
9411 * length overflows 32-bit non-negative integer.
9412 */
9413class ArrayConcatVisitor {
9414 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 ArrayConcatVisitor(Isolate* isolate,
9416 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009417 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 isolate_(isolate),
9419 storage_(Handle<FixedArray>::cast(
9420 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009421 index_offset_(0u),
9422 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009423
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009424 ~ArrayConcatVisitor() {
9425 clear_storage();
9426 }
9427
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009428 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009429 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009430 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009431
9432 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009433 if (index < static_cast<uint32_t>(storage_->length())) {
9434 storage_->set(index, *elm);
9435 return;
9436 }
9437 // Our initial estimate of length was foiled, possibly by
9438 // getters on the arrays increasing the length of later arrays
9439 // during iteration.
9440 // This shouldn't happen in anything but pathological cases.
9441 SetDictionaryMode(index);
9442 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009443 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009444 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009445 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009446 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009447 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009449 // Dictionary needed to grow.
9450 clear_storage();
9451 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009452 }
9453}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009454
9455 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009456 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9457 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009458 } else {
9459 index_offset_ += delta;
9460 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009461 }
9462
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009463 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009465 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009466 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009467 Handle<Map> map;
9468 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009469 map = isolate_->factory()->GetElementsTransitionMap(array,
9470 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009471 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009472 map = isolate_->factory()->GetElementsTransitionMap(array,
9473 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 }
9475 array->set_map(*map);
9476 array->set_length(*length);
9477 array->set_elements(*storage_);
9478 return array;
9479 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009480
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009481 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009482 // Convert storage to dictionary mode.
9483 void SetDictionaryMode(uint32_t index) {
9484 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009485 Handle<FixedArray> current_storage(*storage_);
9486 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009487 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009488 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9489 for (uint32_t i = 0; i < current_length; i++) {
9490 HandleScope loop_scope;
9491 Handle<Object> element(current_storage->get(i));
9492 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009493 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009495 if (!new_storage.is_identical_to(slow_storage)) {
9496 slow_storage = loop_scope.CloseAndEscape(new_storage);
9497 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009498 }
9499 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009500 clear_storage();
9501 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009502 fast_elements_ = false;
9503 }
9504
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009505 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009506 isolate_->global_handles()->Destroy(
9507 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009508 }
9509
9510 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 storage_ = Handle<FixedArray>::cast(
9512 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009513 }
9514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009515 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009516 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009517 // Index after last seen index. Always less than or equal to
9518 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009519 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009520 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009521};
9522
9523
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009524static uint32_t EstimateElementCount(Handle<JSArray> array) {
9525 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9526 int element_count = 0;
9527 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009528 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009529 // Fast elements can't have lengths that are not representable by
9530 // a 32-bit signed integer.
9531 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9532 int fast_length = static_cast<int>(length);
9533 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9534 for (int i = 0; i < fast_length; i++) {
9535 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009536 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009537 break;
9538 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009539 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 Handle<NumberDictionary> dictionary(
9541 NumberDictionary::cast(array->elements()));
9542 int capacity = dictionary->Capacity();
9543 for (int i = 0; i < capacity; i++) {
9544 Handle<Object> key(dictionary->KeyAt(i));
9545 if (dictionary->IsKey(*key)) {
9546 element_count++;
9547 }
9548 }
9549 break;
9550 }
9551 default:
9552 // External arrays are always dense.
9553 return length;
9554 }
9555 // As an estimate, we assume that the prototype doesn't contain any
9556 // inherited elements.
9557 return element_count;
9558}
9559
9560
9561
9562template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009563static void IterateExternalArrayElements(Isolate* isolate,
9564 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009565 bool elements_are_ints,
9566 bool elements_are_guaranteed_smis,
9567 ArrayConcatVisitor* visitor) {
9568 Handle<ExternalArrayClass> array(
9569 ExternalArrayClass::cast(receiver->elements()));
9570 uint32_t len = static_cast<uint32_t>(array->length());
9571
9572 ASSERT(visitor != NULL);
9573 if (elements_are_ints) {
9574 if (elements_are_guaranteed_smis) {
9575 for (uint32_t j = 0; j < len; j++) {
9576 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009577 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 visitor->visit(j, e);
9579 }
9580 } else {
9581 for (uint32_t j = 0; j < len; j++) {
9582 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009583 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009584 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9585 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9586 visitor->visit(j, e);
9587 } else {
9588 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 visitor->visit(j, e);
9591 }
9592 }
9593 }
9594 } else {
9595 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009597 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 visitor->visit(j, e);
9599 }
9600 }
9601}
9602
9603
9604// Used for sorting indices in a List<uint32_t>.
9605static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9606 uint32_t a = *ap;
9607 uint32_t b = *bp;
9608 return (a == b) ? 0 : (a < b) ? -1 : 1;
9609}
9610
9611
9612static void CollectElementIndices(Handle<JSObject> object,
9613 uint32_t range,
9614 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009615 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009617 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009618 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009619 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9620 uint32_t length = static_cast<uint32_t>(elements->length());
9621 if (range < length) length = range;
9622 for (uint32_t i = 0; i < length; i++) {
9623 if (!elements->get(i)->IsTheHole()) {
9624 indices->Add(i);
9625 }
9626 }
9627 break;
9628 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009629 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009630 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009631 uint32_t capacity = dict->Capacity();
9632 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009634 Handle<Object> k(dict->KeyAt(j));
9635 if (dict->IsKey(*k)) {
9636 ASSERT(k->IsNumber());
9637 uint32_t index = static_cast<uint32_t>(k->Number());
9638 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009639 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009640 }
9641 }
9642 }
9643 break;
9644 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 default: {
9646 int dense_elements_length;
9647 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009648 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009649 dense_elements_length =
9650 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 break;
9652 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009653 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009654 dense_elements_length =
9655 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 break;
9657 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009658 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009659 dense_elements_length =
9660 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 break;
9662 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009663 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009664 dense_elements_length =
9665 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009666 break;
9667 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009668 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009669 dense_elements_length =
9670 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 break;
9672 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009673 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009674 dense_elements_length =
9675 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 break;
9677 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009678 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009679 dense_elements_length =
9680 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 break;
9682 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009683 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009684 dense_elements_length =
9685 ExternalFloatArray::cast(object->elements())->length();
9686 break;
9687 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009688 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009689 dense_elements_length =
9690 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 break;
9692 }
9693 default:
9694 UNREACHABLE();
9695 dense_elements_length = 0;
9696 break;
9697 }
9698 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9699 if (range <= length) {
9700 length = range;
9701 // We will add all indices, so we might as well clear it first
9702 // and avoid duplicates.
9703 indices->Clear();
9704 }
9705 for (uint32_t i = 0; i < length; i++) {
9706 indices->Add(i);
9707 }
9708 if (length == range) return; // All indices accounted for already.
9709 break;
9710 }
9711 }
9712
9713 Handle<Object> prototype(object->GetPrototype());
9714 if (prototype->IsJSObject()) {
9715 // The prototype will usually have no inherited element indices,
9716 // but we have to check.
9717 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9718 }
9719}
9720
9721
9722/**
9723 * A helper function that visits elements of a JSArray in numerical
9724 * order.
9725 *
9726 * The visitor argument called for each existing element in the array
9727 * with the element index and the element's value.
9728 * Afterwards it increments the base-index of the visitor by the array
9729 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009730 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009732static bool IterateElements(Isolate* isolate,
9733 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 ArrayConcatVisitor* visitor) {
9735 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9736 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009737 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009738 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009739 // Run through the elements FixedArray and use HasElement and GetElement
9740 // to check the prototype for missing elements.
9741 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9742 int fast_length = static_cast<int>(length);
9743 ASSERT(fast_length <= elements->length());
9744 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745 HandleScope loop_scope(isolate);
9746 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 if (!element_value->IsTheHole()) {
9748 visitor->visit(j, element_value);
9749 } else if (receiver->HasElement(j)) {
9750 // Call GetElement on receiver, not its prototype, or getters won't
9751 // have the correct receiver.
9752 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009753 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 visitor->visit(j, element_value);
9755 }
9756 }
9757 break;
9758 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009759 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009760 Handle<NumberDictionary> dict(receiver->element_dictionary());
9761 List<uint32_t> indices(dict->Capacity() / 2);
9762 // Collect all indices in the object and the prototypes less
9763 // than length. This might introduce duplicates in the indices list.
9764 CollectElementIndices(receiver, length, &indices);
9765 indices.Sort(&compareUInt32);
9766 int j = 0;
9767 int n = indices.length();
9768 while (j < n) {
9769 HandleScope loop_scope;
9770 uint32_t index = indices[j];
9771 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009772 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 visitor->visit(index, element);
9774 // Skip to next different index (i.e., omit duplicates).
9775 do {
9776 j++;
9777 } while (j < n && indices[j] == index);
9778 }
9779 break;
9780 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009781 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009782 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9783 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009785 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009786 visitor->visit(j, e);
9787 }
9788 break;
9789 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009790 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009791 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009792 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009793 break;
9794 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009795 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009796 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009798 break;
9799 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009800 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009801 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009802 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009803 break;
9804 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009805 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009806 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009807 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 break;
9809 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009810 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009811 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009812 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 break;
9814 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009815 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009816 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 break;
9819 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009820 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009823 break;
9824 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009825 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009826 IterateExternalArrayElements<ExternalDoubleArray, double>(
9827 isolate, receiver, false, false, visitor);
9828 break;
9829 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009830 default:
9831 UNREACHABLE();
9832 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009833 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009835 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009836}
9837
9838
9839/**
9840 * Array::concat implementation.
9841 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009843 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009844 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009845RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009846 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009847 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009848
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9850 int argument_count = static_cast<int>(arguments->length()->Number());
9851 RUNTIME_ASSERT(arguments->HasFastElements());
9852 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009853
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 // Pass 1: estimate the length and number of elements of the result.
9855 // The actual length can be larger if any of the arguments have getters
9856 // that mutate other arguments (but will otherwise be precise).
9857 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009858
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 uint32_t estimate_result_length = 0;
9860 uint32_t estimate_nof_elements = 0;
9861 {
9862 for (int i = 0; i < argument_count; i++) {
9863 HandleScope loop_scope;
9864 Handle<Object> obj(elements->get(i));
9865 uint32_t length_estimate;
9866 uint32_t element_estimate;
9867 if (obj->IsJSArray()) {
9868 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9869 length_estimate =
9870 static_cast<uint32_t>(array->length()->Number());
9871 element_estimate =
9872 EstimateElementCount(array);
9873 } else {
9874 length_estimate = 1;
9875 element_estimate = 1;
9876 }
9877 // Avoid overflows by capping at kMaxElementCount.
9878 if (JSObject::kMaxElementCount - estimate_result_length <
9879 length_estimate) {
9880 estimate_result_length = JSObject::kMaxElementCount;
9881 } else {
9882 estimate_result_length += length_estimate;
9883 }
9884 if (JSObject::kMaxElementCount - estimate_nof_elements <
9885 element_estimate) {
9886 estimate_nof_elements = JSObject::kMaxElementCount;
9887 } else {
9888 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009889 }
9890 }
9891 }
9892
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009893 // If estimated number of elements is more than half of length, a
9894 // fixed array (fast case) is more time and space-efficient than a
9895 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009896 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009897
9898 Handle<FixedArray> storage;
9899 if (fast_case) {
9900 // The backing storage array must have non-existing elements to
9901 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009902 storage = isolate->factory()->NewFixedArrayWithHoles(
9903 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009904 } else {
9905 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9906 uint32_t at_least_space_for = estimate_nof_elements +
9907 (estimate_nof_elements >> 2);
9908 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009909 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009910 }
9911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009913
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009914 for (int i = 0; i < argument_count; i++) {
9915 Handle<Object> obj(elements->get(i));
9916 if (obj->IsJSArray()) {
9917 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009918 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009919 return Failure::Exception();
9920 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009921 } else {
9922 visitor.visit(0, obj);
9923 visitor.increase_index_offset(1);
9924 }
9925 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009926
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009928}
9929
9930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931// This will not allocate (flatten the string), but it may run
9932// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009933RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934 NoHandleAllocation ha;
9935 ASSERT(args.length() == 1);
9936
9937 CONVERT_CHECKED(String, string, args[0]);
9938 StringInputBuffer buffer(string);
9939 while (buffer.has_more()) {
9940 uint16_t character = buffer.GetNext();
9941 PrintF("%c", character);
9942 }
9943 return string;
9944}
9945
ager@chromium.org5ec48922009-05-05 07:25:34 +00009946// Moves all own elements of an object, that are below a limit, to positions
9947// starting at zero. All undefined values are placed after non-undefined values,
9948// and are followed by non-existing element. Does not change the length
9949// property.
9950// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009951RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009952 ASSERT(args.length() == 2);
9953 CONVERT_CHECKED(JSObject, object, args[0]);
9954 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9955 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956}
9957
9958
9959// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009960RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 ASSERT(args.length() == 2);
9962 CONVERT_CHECKED(JSArray, from, args[0]);
9963 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009964 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009965 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009966 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9968 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009969 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009970 } else if (new_elements->map() ==
9971 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009972 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009973 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009974 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009975 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009976 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009977 Object* new_map;
9978 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009979 to->set_map(Map::cast(new_map));
9980 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009982 Object* obj;
9983 { MaybeObject* maybe_obj = from->ResetElements();
9984 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9985 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009986 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009987 return to;
9988}
9989
9990
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009991// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009992RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009994 CONVERT_CHECKED(JSObject, object, args[0]);
9995 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009997 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009998 } else if (object->IsJSArray()) {
9999 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010001 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 }
10003}
10004
10005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010006RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010008
10009 ASSERT_EQ(3, args.length());
10010
ager@chromium.orgac091b72010-05-05 07:34:42 +000010011 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010012 Handle<Object> key1 = args.at<Object>(1);
10013 Handle<Object> key2 = args.at<Object>(2);
10014
10015 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010016 if (!key1->ToArrayIndex(&index1)
10017 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010019 }
10020
ager@chromium.orgac091b72010-05-05 07:34:42 +000010021 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
10022 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010023 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010024 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010027 RETURN_IF_EMPTY_HANDLE(isolate,
10028 SetElement(jsobject, index1, tmp2, kStrictMode));
10029 RETURN_IF_EMPTY_HANDLE(isolate,
10030 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010032 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010033}
10034
10035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010036// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010037// might have elements. Can either return keys (positive integers) or
10038// intervals (pair of a negative integer (-start-1) followed by a
10039// positive (length)) or undefined values.
10040// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010041RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010044 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010046 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 // Create an array and get all the keys into it, then remove all the
10048 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010049 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050 int keys_length = keys->length();
10051 for (int i = 0; i < keys_length; i++) {
10052 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010053 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010054 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055 // Zap invalid keys.
10056 keys->set_undefined(i);
10057 }
10058 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010060 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010061 ASSERT(array->HasFastElements() ||
10062 array->HasFastSmiOnlyElements() ||
10063 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010066 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010067 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010068 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010069 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010070 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010074 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010075 }
10076}
10077
10078
10079// DefineAccessor takes an optional final argument which is the
10080// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10081// to the way accessors are implemented, it is set for both the getter
10082// and setter on the first call to DefineAccessor and ignored on
10083// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010084RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010085 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10086 // Compute attributes.
10087 PropertyAttributes attributes = NONE;
10088 if (args.length() == 5) {
10089 CONVERT_CHECKED(Smi, attrs, args[4]);
10090 int value = attrs->value();
10091 // Only attribute bits should be set.
10092 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10093 attributes = static_cast<PropertyAttributes>(value);
10094 }
10095
10096 CONVERT_CHECKED(JSObject, obj, args[0]);
10097 CONVERT_CHECKED(String, name, args[1]);
10098 CONVERT_CHECKED(Smi, flag, args[2]);
10099 CONVERT_CHECKED(JSFunction, fun, args[3]);
10100 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10101}
10102
10103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010104RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 ASSERT(args.length() == 3);
10106 CONVERT_CHECKED(JSObject, obj, args[0]);
10107 CONVERT_CHECKED(String, name, args[1]);
10108 CONVERT_CHECKED(Smi, flag, args[2]);
10109 return obj->LookupAccessor(name, flag->value() == 0);
10110}
10111
10112
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010113#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010114RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010115 ASSERT(args.length() == 0);
10116 return Execution::DebugBreakHelper();
10117}
10118
10119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010120// Helper functions for wrapping and unwrapping stack frame ids.
10121static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010122 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123 return Smi::FromInt(id >> 2);
10124}
10125
10126
10127static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10128 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10129}
10130
10131
10132// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010133// args[0]: debug event listener function to set or null or undefined for
10134// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010138 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10139 args[0]->IsUndefined() ||
10140 args[0]->IsNull());
10141 Handle<Object> callback = args.at<Object>(0);
10142 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010145 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010146}
10147
10148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010149RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010150 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010151 isolate->stack_guard()->DebugBreak();
10152 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010153}
10154
10155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156static MaybeObject* DebugLookupResultValue(Heap* heap,
10157 Object* receiver,
10158 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010159 LookupResult* result,
10160 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010161 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010163 case NORMAL:
10164 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010165 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 }
10168 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010169 case FIELD:
10170 value =
10171 JSObject::cast(
10172 result->holder())->FastPropertyAt(result->GetFieldIndex());
10173 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010175 }
10176 return value;
10177 case CONSTANT_FUNCTION:
10178 return result->GetConstantFunction();
10179 case CALLBACKS: {
10180 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010181 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010182 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10183 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010184 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010185 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010186 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010187 maybe_value = heap->isolate()->pending_exception();
10188 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010189 if (caught_exception != NULL) {
10190 *caught_exception = true;
10191 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010192 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010193 }
10194 return value;
10195 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010197 }
10198 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010200 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010201 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010202 case CONSTANT_TRANSITION:
10203 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 default:
10206 UNREACHABLE();
10207 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010208 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210}
10211
10212
ager@chromium.org32912102009-01-16 10:38:43 +000010213// Get debugger related details for an object property.
10214// args[0]: object holding property
10215// args[1]: name of the property
10216//
10217// The array returned contains the following information:
10218// 0: Property value
10219// 1: Property details
10220// 2: Property value is exception
10221// 3: Getter function if defined
10222// 4: Setter function if defined
10223// Items 2-4 are only filled if the property has either a getter or a setter
10224// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010225RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227
10228 ASSERT(args.length() == 2);
10229
10230 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10231 CONVERT_ARG_CHECKED(String, name, 1);
10232
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010233 // Make sure to set the current context to the context before the debugger was
10234 // entered (if the debugger is entered). The reason for switching context here
10235 // is that for some property lookups (accessors and interceptors) callbacks
10236 // into the embedding application can occour, and the embedding application
10237 // could have the assumption that its own global context is the current
10238 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 SaveContext save(isolate);
10240 if (isolate->debug()->InDebugger()) {
10241 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010242 }
10243
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010244 // Skip the global proxy as it has no properties and always delegates to the
10245 // real global object.
10246 if (obj->IsJSGlobalProxy()) {
10247 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10248 }
10249
10250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 // Check if the name is trivially convertible to an index and get the element
10252 // if so.
10253 uint32_t index;
10254 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010255 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010256 Object* element_or_char;
10257 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010259 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10260 return maybe_element_or_char;
10261 }
10262 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010263 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010265 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266 }
10267
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010268 // Find the number of objects making up this.
10269 int length = LocalPrototypeChainLength(*obj);
10270
10271 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010272 Handle<JSObject> jsproto = obj;
10273 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010274 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010275 jsproto->LocalLookup(*name, &result);
10276 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010277 // LookupResult is not GC safe as it holds raw object pointers.
10278 // GC can happen later in this code so put the required fields into
10279 // local variables using handles when required for later use.
10280 PropertyType result_type = result.type();
10281 Handle<Object> result_callback_obj;
10282 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10284 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010285 }
10286 Smi* property_details = result.GetPropertyDetails().AsSmi();
10287 // DebugLookupResultValue can cause GC so details from LookupResult needs
10288 // to be copied to handles before this.
10289 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010290 Object* raw_value;
10291 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010292 DebugLookupResultValue(isolate->heap(), *obj, *name,
10293 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010294 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10295 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010296 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010297
10298 // If the callback object is a fixed array then it contains JavaScript
10299 // getter and/or setter.
10300 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10301 result_callback_obj->IsFixedArray();
10302 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010304 details->set(0, *value);
10305 details->set(1, property_details);
10306 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010307 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010308 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10309 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10310 }
10311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010313 }
10314 if (i < length - 1) {
10315 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10316 }
10317 }
10318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010319 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320}
10321
10322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010323RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325
10326 ASSERT(args.length() == 2);
10327
10328 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10329 CONVERT_ARG_CHECKED(String, name, 1);
10330
10331 LookupResult result;
10332 obj->Lookup(*name, &result);
10333 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337}
10338
10339
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340// Return the property type calculated from the property details.
10341// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010342RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 ASSERT(args.length() == 1);
10344 CONVERT_CHECKED(Smi, details, args[0]);
10345 PropertyType type = PropertyDetails(details).type();
10346 return Smi::FromInt(static_cast<int>(type));
10347}
10348
10349
10350// Return the property attribute calculated from the property details.
10351// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010352RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 ASSERT(args.length() == 1);
10354 CONVERT_CHECKED(Smi, details, args[0]);
10355 PropertyAttributes attributes = PropertyDetails(details).attributes();
10356 return Smi::FromInt(static_cast<int>(attributes));
10357}
10358
10359
10360// Return the property insertion index calculated from the property details.
10361// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010362RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363 ASSERT(args.length() == 1);
10364 CONVERT_CHECKED(Smi, details, args[0]);
10365 int index = PropertyDetails(details).index();
10366 return Smi::FromInt(index);
10367}
10368
10369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370// Return property value from named interceptor.
10371// args[0]: object
10372// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010373RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375 ASSERT(args.length() == 2);
10376 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10377 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10378 CONVERT_ARG_CHECKED(String, name, 1);
10379
10380 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010381 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382}
10383
10384
10385// Return element value from indexed interceptor.
10386// args[0]: object
10387// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010388RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010389 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 ASSERT(args.length() == 2);
10391 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10392 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10393 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10394
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010395 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010396}
10397
10398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010399RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400 ASSERT(args.length() >= 1);
10401 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010402 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 if (isolate->debug()->break_id() == 0 ||
10404 break_id != isolate->debug()->break_id()) {
10405 return isolate->Throw(
10406 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 }
10408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410}
10411
10412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010413RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415 ASSERT(args.length() == 1);
10416
10417 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010418 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010419 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10420 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010421 if (!maybe_result->ToObject(&result)) return maybe_result;
10422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423
10424 // Count all frames which are relevant to debugging stack trace.
10425 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010427 if (id == StackFrame::NO_ID) {
10428 // If there is no JavaScript stack frame count is 0.
10429 return Smi::FromInt(0);
10430 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010431
10432 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10433 n += it.frame()->GetInlineCount();
10434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435 return Smi::FromInt(n);
10436}
10437
10438
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010439class FrameInspector {
10440 public:
10441 FrameInspector(JavaScriptFrame* frame,
10442 int inlined_frame_index,
10443 Isolate* isolate)
10444 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10445 // Calculate the deoptimized frame.
10446 if (frame->is_optimized()) {
10447 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10448 frame, inlined_frame_index, isolate);
10449 }
10450 has_adapted_arguments_ = frame_->has_adapted_arguments();
10451 is_optimized_ = frame_->is_optimized();
10452 }
10453
10454 ~FrameInspector() {
10455 // Get rid of the calculated deoptimized frame if any.
10456 if (deoptimized_frame_ != NULL) {
10457 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10458 isolate_);
10459 }
10460 }
10461
10462 int GetParametersCount() {
10463 return is_optimized_
10464 ? deoptimized_frame_->parameters_count()
10465 : frame_->ComputeParametersCount();
10466 }
10467 int expression_count() { return deoptimized_frame_->expression_count(); }
10468 Object* GetFunction() {
10469 return is_optimized_
10470 ? deoptimized_frame_->GetFunction()
10471 : frame_->function();
10472 }
10473 Object* GetParameter(int index) {
10474 return is_optimized_
10475 ? deoptimized_frame_->GetParameter(index)
10476 : frame_->GetParameter(index);
10477 }
10478 Object* GetExpression(int index) {
10479 return is_optimized_
10480 ? deoptimized_frame_->GetExpression(index)
10481 : frame_->GetExpression(index);
10482 }
10483
10484 // To inspect all the provided arguments the frame might need to be
10485 // replaced with the arguments frame.
10486 void SetArgumentsFrame(JavaScriptFrame* frame) {
10487 ASSERT(has_adapted_arguments_);
10488 frame_ = frame;
10489 is_optimized_ = frame_->is_optimized();
10490 ASSERT(!is_optimized_);
10491 }
10492
10493 private:
10494 JavaScriptFrame* frame_;
10495 DeoptimizedFrameInfo* deoptimized_frame_;
10496 Isolate* isolate_;
10497 bool is_optimized_;
10498 bool has_adapted_arguments_;
10499
10500 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10501};
10502
10503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504static const int kFrameDetailsFrameIdIndex = 0;
10505static const int kFrameDetailsReceiverIndex = 1;
10506static const int kFrameDetailsFunctionIndex = 2;
10507static const int kFrameDetailsArgumentCountIndex = 3;
10508static const int kFrameDetailsLocalCountIndex = 4;
10509static const int kFrameDetailsSourcePositionIndex = 5;
10510static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010511static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010512static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010513static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
10515// Return an array with frame details
10516// args[0]: number: break id
10517// args[1]: number: frame index
10518//
10519// The array returned contains the following information:
10520// 0: Frame id
10521// 1: Receiver
10522// 2: Function
10523// 3: Argument count
10524// 4: Local count
10525// 5: Source position
10526// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010527// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010528// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529// Arguments name, value
10530// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010531// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010532RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 ASSERT(args.length() == 2);
10535
10536 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010537 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010538 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10539 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010540 if (!maybe_check->ToObject(&check)) return maybe_check;
10541 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010543 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544
10545 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010547 if (id == StackFrame::NO_ID) {
10548 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010549 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010550 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010551
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010552 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010555 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010557 if (index < count + it.frame()->GetInlineCount()) break;
10558 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010562 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010563 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010564 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010565 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010566 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010567
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 // Traverse the saved contexts chain to find the active context for the
10569 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010570 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010571 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 save = save->prev();
10573 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010574 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575
10576 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010577 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578
10579 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010581 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010583 // Check for constructor frame. Inlined frames cannot be construct calls.
10584 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010585 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010586 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010588 // Get scope info and read from it for local variable information.
10589 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010590 Handle<SharedFunctionInfo> shared(function->shared());
10591 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010592 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010593 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 // Get the locals names and values into a temporary array.
10596 //
10597 // TODO(1240907): Hide compiler-introduced stack variables
10598 // (e.g. .result)? For users of the debugger, they will probably be
10599 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 Handle<FixedArray> locals =
10601 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010603 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010604 int i = 0;
10605 for (; i < info.number_of_stack_slots(); ++i) {
10606 // Use the value from the stack.
10607 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010608 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010609 }
10610 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010611 // Get the context containing declarations.
10612 Handle<Context> context(
10613 Context::cast(it.frame()->context())->declaration_context());
10614 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010615 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010616 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010618 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 }
10620 }
10621
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010622 // Check whether this frame is positioned at return. If not top
10623 // frame or if the frame is optimized it cannot be at a return.
10624 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010625 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010627 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010628
10629 // If positioned just before return find the value to be returned and add it
10630 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010631 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010632 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010633 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010634 Address internal_frame_sp = NULL;
10635 while (!it2.done()) {
10636 if (it2.frame()->is_internal()) {
10637 internal_frame_sp = it2.frame()->sp();
10638 } else {
10639 if (it2.frame()->is_java_script()) {
10640 if (it2.frame()->id() == it.frame()->id()) {
10641 // The internal frame just before the JavaScript frame contains the
10642 // value to return on top. A debug break at return will create an
10643 // internal frame to store the return value (eax/rax/r0) before
10644 // entering the debug break exit frame.
10645 if (internal_frame_sp != NULL) {
10646 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 Handle<Object>(Memory::Object_at(internal_frame_sp),
10648 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010649 break;
10650 }
10651 }
10652 }
10653
10654 // Indicate that the previous frame was not an internal frame.
10655 internal_frame_sp = NULL;
10656 }
10657 it2.Advance();
10658 }
10659 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010660
10661 // Now advance to the arguments adapter frame (if any). It contains all
10662 // the provided parameters whereas the function frame always have the number
10663 // of arguments matching the functions parameters. The rest of the
10664 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010665 if (it.frame()->has_adapted_arguments()) {
10666 it.AdvanceToArgumentsFrame();
10667 frame_inspector.SetArgumentsFrame(it.frame());
10668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669
10670 // Find the number of arguments to fill. At least fill the number of
10671 // parameters for the function and fill more if more parameters are provided.
10672 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010673 if (argument_count < frame_inspector.GetParametersCount()) {
10674 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010676#ifdef DEBUG
10677 if (it.frame()->is_optimized()) {
10678 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10679 }
10680#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010681
10682 // Calculate the size of the result.
10683 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010684 2 * (argument_count + info.NumberOfLocals()) +
10685 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010687
10688 // Add the frame id.
10689 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10690
10691 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010692 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693
10694 // Add the arguments count.
10695 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10696
10697 // Add the locals count
10698 details->set(kFrameDetailsLocalCountIndex,
10699 Smi::FromInt(info.NumberOfLocals()));
10700
10701 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010702 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10704 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 }
10707
10708 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010711 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010713
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010714 // Add flags to indicate information on whether this frame is
10715 // bit 0: invoked in the debugger context.
10716 // bit 1: optimized frame.
10717 // bit 2: inlined in optimized frame
10718 int flags = 0;
10719 if (*save->context() == *isolate->debug()->debug_context()) {
10720 flags |= 1 << 0;
10721 }
10722 if (it.frame()->is_optimized()) {
10723 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010724 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010725 }
10726 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727
10728 // Fill the dynamic part.
10729 int details_index = kFrameDetailsFirstDynamicIndex;
10730
10731 // Add arguments name and value.
10732 for (int i = 0; i < argument_count; i++) {
10733 // Name of the argument.
10734 if (i < info.number_of_parameters()) {
10735 details->set(details_index++, *info.parameter_name(i));
10736 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010737 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 }
10739
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010740 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010741 if (i < it.frame()->ComputeParametersCount()) {
10742 // Get the value from the stack.
10743 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010745 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 }
10747 }
10748
10749 // Add locals name and value from the temporary copy from the function frame.
10750 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10751 details->set(details_index++, locals->get(i));
10752 }
10753
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010754 // Add the value being returned.
10755 if (at_return) {
10756 details->set(details_index++, *return_value);
10757 }
10758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 // Add the receiver (same as in function frame).
10760 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10761 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010763 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10764 // If the receiver is not a JSObject and the function is not a
10765 // builtin or strict-mode we have hit an optimization where a
10766 // value object is not converted into a wrapped JS objects. To
10767 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 // by creating correct wrapper object based on the calling frame's
10769 // global context.
10770 it.Advance();
10771 Handle<Context> calling_frames_global_context(
10772 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010773 receiver =
10774 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 }
10776 details->set(kFrameDetailsReceiverIndex, *receiver);
10777
10778 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780}
10781
10782
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010783// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010784static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010786 Handle<SerializedScopeInfo> serialized_scope_info,
10787 ScopeInfo<>& scope_info,
10788 Handle<Context> context,
10789 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010790 // Fill all context locals to the context extension.
10791 for (int i = Context::MIN_CONTEXT_SLOTS;
10792 i < scope_info.number_of_context_slots();
10793 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010794 int context_index = serialized_scope_info->ContextSlotIndex(
10795 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010796
whesse@chromium.org7b260152011-06-20 15:33:18 +000010797 RETURN_IF_EMPTY_HANDLE_VALUE(
10798 isolate,
10799 SetProperty(scope_object,
10800 scope_info.context_slot_name(i),
10801 Handle<Object>(context->get(context_index), isolate),
10802 NONE,
10803 kNonStrictMode),
10804 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010805 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010806
10807 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010808}
10809
10810
10811// Create a plain JSObject which materializes the local scope for the specified
10812// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010813static Handle<JSObject> MaterializeLocalScope(
10814 Isolate* isolate,
10815 JavaScriptFrame* frame,
10816 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010817 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010818 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010819 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10820 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010821 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010822
10823 // Allocate and initialize a JSObject with all the arguments, stack locals
10824 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 Handle<JSObject> local_scope =
10826 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010827
10828 // First fill all parameters.
10829 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010830 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010832 SetProperty(local_scope,
10833 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010834 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010835 NONE,
10836 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010837 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010838 }
10839
10840 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010841 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010842 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010844 SetProperty(local_scope,
10845 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010846 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010847 NONE,
10848 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010849 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010850 }
10851
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010852 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10853 // Third fill all context locals.
10854 Handle<Context> frame_context(Context::cast(frame->context()));
10855 Handle<Context> function_context(frame_context->declaration_context());
10856 if (!CopyContextLocalsToScopeObject(isolate,
10857 serialized_scope_info, scope_info,
10858 function_context, local_scope)) {
10859 return Handle<JSObject>();
10860 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010861
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010862 // Finally copy any properties from the function context extension.
10863 // These will be variables introduced by eval.
10864 if (function_context->closure() == *function) {
10865 if (function_context->has_extension() &&
10866 !function_context->IsGlobalContext()) {
10867 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10868 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10869 for (int i = 0; i < keys->length(); i++) {
10870 // Names of variables introduced by eval are strings.
10871 ASSERT(keys->get(i)->IsString());
10872 Handle<String> key(String::cast(keys->get(i)));
10873 RETURN_IF_EMPTY_HANDLE_VALUE(
10874 isolate,
10875 SetProperty(local_scope,
10876 key,
10877 GetProperty(ext, key),
10878 NONE,
10879 kNonStrictMode),
10880 Handle<JSObject>());
10881 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010882 }
10883 }
10884 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010885
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010886 return local_scope;
10887}
10888
10889
10890// Create a plain JSObject which materializes the closure content for the
10891// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010892static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10893 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010894 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010895
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010896 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010897 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10898 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010899
10900 // Allocate and initialize a JSObject with all the content of theis function
10901 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010902 Handle<JSObject> closure_scope =
10903 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010904
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010905 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010906 if (!CopyContextLocalsToScopeObject(isolate,
10907 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010908 context, closure_scope)) {
10909 return Handle<JSObject>();
10910 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010911
10912 // Finally copy any properties from the function context extension. This will
10913 // be variables introduced by eval.
10914 if (context->has_extension()) {
10915 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010916 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010917 for (int i = 0; i < keys->length(); i++) {
10918 // Names of variables introduced by eval are strings.
10919 ASSERT(keys->get(i)->IsString());
10920 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010921 RETURN_IF_EMPTY_HANDLE_VALUE(
10922 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010923 SetProperty(closure_scope,
10924 key,
10925 GetProperty(ext, key),
10926 NONE,
10927 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010928 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010929 }
10930 }
10931
10932 return closure_scope;
10933}
10934
10935
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010936// Create a plain JSObject which materializes the scope for the specified
10937// catch context.
10938static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10939 Handle<Context> context) {
10940 ASSERT(context->IsCatchContext());
10941 Handle<String> name(String::cast(context->extension()));
10942 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10943 Handle<JSObject> catch_scope =
10944 isolate->factory()->NewJSObject(isolate->object_function());
10945 RETURN_IF_EMPTY_HANDLE_VALUE(
10946 isolate,
10947 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10948 Handle<JSObject>());
10949 return catch_scope;
10950}
10951
10952
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010953// Create a plain JSObject which materializes the block scope for the specified
10954// block context.
10955static Handle<JSObject> MaterializeBlockScope(
10956 Isolate* isolate,
10957 Handle<Context> context) {
10958 ASSERT(context->IsBlockContext());
10959 Handle<SerializedScopeInfo> serialized_scope_info(
10960 SerializedScopeInfo::cast(context->extension()));
10961 ScopeInfo<> scope_info(*serialized_scope_info);
10962
10963 // Allocate and initialize a JSObject with all the arguments, stack locals
10964 // heap locals and extension properties of the debugged function.
10965 Handle<JSObject> block_scope =
10966 isolate->factory()->NewJSObject(isolate->object_function());
10967
10968 // Fill all context locals.
10969 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10970 if (!CopyContextLocalsToScopeObject(isolate,
10971 serialized_scope_info, scope_info,
10972 context, block_scope)) {
10973 return Handle<JSObject>();
10974 }
10975 }
10976
10977 return block_scope;
10978}
10979
10980
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010981// Iterate over the actual scopes visible from a stack frame. All scopes are
10982// backed by an actual context except the local scope, which is inserted
10983// "artifically" in the context chain.
10984class ScopeIterator {
10985 public:
10986 enum ScopeType {
10987 ScopeTypeGlobal = 0,
10988 ScopeTypeLocal,
10989 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010990 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010991 ScopeTypeCatch,
10992 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993 };
10994
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010995 ScopeIterator(Isolate* isolate,
10996 JavaScriptFrame* frame,
10997 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 : isolate_(isolate),
10999 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011000 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011001 function_(JSFunction::cast(frame->function())),
11002 context_(Context::cast(frame->context())),
11003 local_done_(false),
11004 at_local_(false) {
11005
11006 // Check whether the first scope is actually a local scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011007 // If there is a stack slot for .result then this local scope has been
11008 // created for evaluating top level code and it is not a real local scope.
11009 // Checking for the existence of .result seems fragile, but the scope info
11010 // saved with the code object does not otherwise have that information.
11011 int index = function_->shared()->scope_info()->
11012 StackSlotIndex(isolate_->heap()->result_symbol());
11013 if (index >= 0) {
11014 local_done_ = true;
11015 } else if (context_->IsGlobalContext() ||
11016 context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011018 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011019 // The context_ is a block or with or catch block from the outer function.
11020 ASSERT(context_->IsWithContext() ||
11021 context_->IsCatchContext() ||
11022 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011023 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011024 }
11025 }
11026
11027 // More scopes?
11028 bool Done() { return context_.is_null(); }
11029
11030 // Move to the next scope.
11031 void Next() {
11032 // If at a local scope mark the local scope as passed.
11033 if (at_local_) {
11034 at_local_ = false;
11035 local_done_ = true;
11036
11037 // If the current context is not associated with the local scope the
11038 // current context is the next real scope, so don't move to the next
11039 // context in this case.
11040 if (context_->closure() != *function_) {
11041 return;
11042 }
11043 }
11044
11045 // The global scope is always the last in the chain.
11046 if (context_->IsGlobalContext()) {
11047 context_ = Handle<Context>();
11048 return;
11049 }
11050
11051 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011052 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011053
11054 // If passing the local scope indicate that the current scope is now the
11055 // local scope.
11056 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011057 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011058 at_local_ = true;
11059 }
11060 }
11061
11062 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011063 ScopeType Type() {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 if (at_local_) {
11065 return ScopeTypeLocal;
11066 }
11067 if (context_->IsGlobalContext()) {
11068 ASSERT(context_->global()->IsGlobalObject());
11069 return ScopeTypeGlobal;
11070 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011071 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011072 return ScopeTypeClosure;
11073 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011074 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011075 return ScopeTypeCatch;
11076 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011077 if (context_->IsBlockContext()) {
11078 return ScopeTypeBlock;
11079 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011080 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081 return ScopeTypeWith;
11082 }
11083
11084 // Return the JavaScript object with the content of the current scope.
11085 Handle<JSObject> ScopeObject() {
11086 switch (Type()) {
11087 case ScopeIterator::ScopeTypeGlobal:
11088 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089 case ScopeIterator::ScopeTypeLocal:
11090 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011091 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011092 case ScopeIterator::ScopeTypeWith:
11093 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011094 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11095 case ScopeIterator::ScopeTypeCatch:
11096 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097 case ScopeIterator::ScopeTypeClosure:
11098 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011100 case ScopeIterator::ScopeTypeBlock:
11101 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102 }
11103 UNREACHABLE();
11104 return Handle<JSObject>();
11105 }
11106
11107 // Return the context for this scope. For the local context there might not
11108 // be an actual context.
11109 Handle<Context> CurrentContext() {
11110 if (at_local_ && context_->closure() != *function_) {
11111 return Handle<Context>();
11112 }
11113 return context_;
11114 }
11115
11116#ifdef DEBUG
11117 // Debug print of the content of the current scope.
11118 void DebugPrint() {
11119 switch (Type()) {
11120 case ScopeIterator::ScopeTypeGlobal:
11121 PrintF("Global:\n");
11122 CurrentContext()->Print();
11123 break;
11124
11125 case ScopeIterator::ScopeTypeLocal: {
11126 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011127 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128 scope_info.Print();
11129 if (!CurrentContext().is_null()) {
11130 CurrentContext()->Print();
11131 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011132 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011133 if (extension->IsJSContextExtensionObject()) {
11134 extension->Print();
11135 }
11136 }
11137 }
11138 break;
11139 }
11140
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011141 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011142 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011143 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011145
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011146 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011147 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011148 CurrentContext()->extension()->Print();
11149 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011150 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011151
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011152 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011153 PrintF("Closure:\n");
11154 CurrentContext()->Print();
11155 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011156 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011157 if (extension->IsJSContextExtensionObject()) {
11158 extension->Print();
11159 }
11160 }
11161 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011162
11163 default:
11164 UNREACHABLE();
11165 }
11166 PrintF("\n");
11167 }
11168#endif
11169
11170 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011171 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011172 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011173 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174 Handle<JSFunction> function_;
11175 Handle<Context> context_;
11176 bool local_done_;
11177 bool at_local_;
11178
11179 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11180};
11181
11182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011184 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 ASSERT(args.length() == 2);
11186
11187 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011188 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011189 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11190 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011191 if (!maybe_check->ToObject(&check)) return maybe_check;
11192 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11194
11195 // Get the frame where the debugging is performed.
11196 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011197 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198 JavaScriptFrame* frame = it.frame();
11199
11200 // Count the visible scopes.
11201 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011202 for (ScopeIterator it(isolate, frame, 0);
11203 !it.Done();
11204 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205 n++;
11206 }
11207
11208 return Smi::FromInt(n);
11209}
11210
11211
11212static const int kScopeDetailsTypeIndex = 0;
11213static const int kScopeDetailsObjectIndex = 1;
11214static const int kScopeDetailsSize = 2;
11215
11216// Return an array with scope details
11217// args[0]: number: break id
11218// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011219// args[2]: number: inlined frame index
11220// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011221//
11222// The array returned contains the following information:
11223// 0: Scope type
11224// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011225RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011226 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011227 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228
11229 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011230 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011231 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11232 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011233 if (!maybe_check->ToObject(&check)) return maybe_check;
11234 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011235 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011236 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11237 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011238
11239 // Get the frame where the debugging is performed.
11240 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011241 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011242 JavaScriptFrame* frame = frame_it.frame();
11243
11244 // Find the requested scope.
11245 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011246 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011247 for (; !it.Done() && n < index; it.Next()) {
11248 n++;
11249 }
11250 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011251 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011252 }
11253
11254 // Calculate the size of the result.
11255 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257
11258 // Fill in scope details.
11259 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011260 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011261 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011262 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011263
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011264 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011265}
11266
11267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011268RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011270 ASSERT(args.length() == 0);
11271
11272#ifdef DEBUG
11273 // Print the scopes for the top frame.
11274 StackFrameLocator locator;
11275 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011276 for (ScopeIterator it(isolate, frame, 0);
11277 !it.Done();
11278 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011279 it.DebugPrint();
11280 }
11281#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011282 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283}
11284
11285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011286RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011288 ASSERT(args.length() == 1);
11289
11290 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011291 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011292 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11293 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011294 if (!maybe_result->ToObject(&result)) return maybe_result;
11295 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011296
11297 // Count all archived V8 threads.
11298 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011299 for (ThreadState* thread =
11300 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011301 thread != NULL;
11302 thread = thread->Next()) {
11303 n++;
11304 }
11305
11306 // Total number of threads is current thread and archived threads.
11307 return Smi::FromInt(n + 1);
11308}
11309
11310
11311static const int kThreadDetailsCurrentThreadIndex = 0;
11312static const int kThreadDetailsThreadIdIndex = 1;
11313static const int kThreadDetailsSize = 2;
11314
11315// Return an array with thread details
11316// args[0]: number: break id
11317// args[1]: number: thread index
11318//
11319// The array returned contains the following information:
11320// 0: Is current thread?
11321// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011322RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011323 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011324 ASSERT(args.length() == 2);
11325
11326 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011327 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011328 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11329 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011330 if (!maybe_check->ToObject(&check)) return maybe_check;
11331 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011332 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11333
11334 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 Handle<FixedArray> details =
11336 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011337
11338 // Thread index 0 is current thread.
11339 if (index == 0) {
11340 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 details->set(kThreadDetailsCurrentThreadIndex,
11342 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011343 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011344 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011345 } else {
11346 // Find the thread with the requested index.
11347 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011348 ThreadState* thread =
11349 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011350 while (index != n && thread != NULL) {
11351 thread = thread->Next();
11352 n++;
11353 }
11354 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011355 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011356 }
11357
11358 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011359 details->set(kThreadDetailsCurrentThreadIndex,
11360 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011361 details->set(kThreadDetailsThreadIdIndex,
11362 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011363 }
11364
11365 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011366 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011367}
11368
11369
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011370// Sets the disable break state
11371// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011372RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011373 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011374 ASSERT(args.length() == 1);
11375 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011376 isolate->debug()->set_disable_break(disable_break);
11377 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011378}
11379
11380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383 ASSERT(args.length() == 1);
11384
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011385 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11386 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011387 // Find the number of break points
11388 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011390 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 Handle<FixedArray>::cast(break_locations));
11393}
11394
11395
11396// Set a break point in a function
11397// args[0]: function
11398// args[1]: number: break source position (within the function source)
11399// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011400RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011402 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011403 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11404 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011405 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11406 RUNTIME_ASSERT(source_position >= 0);
11407 Handle<Object> break_point_object_arg = args.at<Object>(2);
11408
11409 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11411 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011412
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011413 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414}
11415
11416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11418 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011419 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420 // Iterate the heap looking for SharedFunctionInfo generated from the
11421 // script. The inner most SharedFunctionInfo containing the source position
11422 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011423 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 // which is found is not compiled it is compiled and the heap is iterated
11425 // again as the compilation might create inner functions from the newly
11426 // compiled function and the actual requested break point might be in one of
11427 // these functions.
11428 bool done = false;
11429 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011430 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011431 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011432 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011433 { // Extra scope for iterator and no-allocation.
11434 isolate->heap()->EnsureHeapIsIterable();
11435 AssertNoAllocation no_alloc_during_heap_iteration;
11436 HeapIterator iterator;
11437 for (HeapObject* obj = iterator.next();
11438 obj != NULL; obj = iterator.next()) {
11439 if (obj->IsSharedFunctionInfo()) {
11440 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11441 if (shared->script() == *script) {
11442 // If the SharedFunctionInfo found has the requested script data and
11443 // contains the source position it is a candidate.
11444 int start_position = shared->function_token_position();
11445 if (start_position == RelocInfo::kNoPosition) {
11446 start_position = shared->start_position();
11447 }
11448 if (start_position <= position &&
11449 position <= shared->end_position()) {
11450 // If there is no candidate or this function is within the current
11451 // candidate this is the new candidate.
11452 if (target.is_null()) {
11453 target_start_position = start_position;
11454 target = shared;
11455 } else {
11456 if (target_start_position == start_position &&
11457 shared->end_position() == target->end_position()) {
11458 // If a top-level function contain only one function
11459 // declartion the source for the top-level and the
11460 // function is the same. In that case prefer the non
11461 // top-level function.
11462 if (!shared->is_toplevel()) {
11463 target_start_position = start_position;
11464 target = shared;
11465 }
11466 } else if (target_start_position <= start_position &&
11467 shared->end_position() <= target->end_position()) {
11468 // This containment check includes equality as a function
11469 // inside a top-level function can share either start or end
11470 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011471 target_start_position = start_position;
11472 target = shared;
11473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 }
11475 }
11476 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011477 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011478 } // End for loop.
11479 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011481 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011482 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011483 }
11484
11485 // If the candidate found is compiled we are done. NOTE: when lazy
11486 // compilation of inner functions is introduced some additional checking
11487 // needs to be done here to compile inner functions.
11488 done = target->is_compiled();
11489 if (!done) {
11490 // If the candidate is not compiled compile it to reveal any inner
11491 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011492 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011493 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011494 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011495
11496 return *target;
11497}
11498
11499
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011500// Changes the state of a break point in a script and returns source position
11501// where break point was set. NOTE: Regarding performance see the NOTE for
11502// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011503// args[0]: script to set break point in
11504// args[1]: number: break source position (within the script source)
11505// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011506RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011508 ASSERT(args.length() == 3);
11509 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11510 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11511 RUNTIME_ASSERT(source_position >= 0);
11512 Handle<Object> break_point_object_arg = args.at<Object>(2);
11513
11514 // Get the script from the script wrapper.
11515 RUNTIME_ASSERT(wrapper->value()->IsScript());
11516 Handle<Script> script(Script::cast(wrapper->value()));
11517
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011518 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520 if (!result->IsUndefined()) {
11521 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11522 // Find position within function. The script position might be before the
11523 // source position of the first function.
11524 int position;
11525 if (shared->start_position() > source_position) {
11526 position = 0;
11527 } else {
11528 position = source_position - shared->start_position();
11529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011531 position += shared->start_position();
11532 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535}
11536
11537
11538// Clear a break point
11539// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011540RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 ASSERT(args.length() == 1);
11543 Handle<Object> break_point_object_arg = args.at<Object>(0);
11544
11545 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549}
11550
11551
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011552// Change the state of break on exceptions.
11553// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11554// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011555RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011556 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011558 RUNTIME_ASSERT(args[0]->IsNumber());
11559 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011560
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011561 // If the number doesn't match an enum value, the ChangeBreakOnException
11562 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 ExceptionBreakType type =
11564 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011565 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 isolate->debug()->ChangeBreakOnException(type, enable);
11567 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011568}
11569
11570
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011571// Returns the state of break on exceptions
11572// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011573RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011575 ASSERT(args.length() == 1);
11576 RUNTIME_ASSERT(args[0]->IsNumber());
11577
11578 ExceptionBreakType type =
11579 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011581 return Smi::FromInt(result);
11582}
11583
11584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585// Prepare for stepping
11586// args[0]: break id for checking execution state
11587// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011588// args[2]: number of times to perform the step, for step out it is the number
11589// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011590RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592 ASSERT(args.length() == 3);
11593 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011594 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11596 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011597 if (!maybe_check->ToObject(&check)) return maybe_check;
11598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011599 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601 }
11602
11603 // Get the step action and check validity.
11604 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11605 if (step_action != StepIn &&
11606 step_action != StepNext &&
11607 step_action != StepOut &&
11608 step_action != StepInMin &&
11609 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011610 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011611 }
11612
11613 // Get the number of steps.
11614 int step_count = NumberToInt32(args[2]);
11615 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011617 }
11618
ager@chromium.orga1645e22009-09-09 19:27:10 +000011619 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011622 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11624 step_count);
11625 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626}
11627
11628
11629// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011630RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011632 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 isolate->debug()->ClearStepping();
11634 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011635}
11636
11637
11638// Creates a copy of the with context chain. The copy of the context chain is
11639// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011640static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011641 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011642 Handle<Context> current,
11643 Handle<Context> base) {
11644 // At the end of the chain. Return the base context to link to.
11645 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11646 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 }
11648
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011649 // Recursively copy the with and catch contexts.
11650 HandleScope scope(isolate);
11651 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011652 Handle<Context> new_previous =
11653 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011654 Handle<Context> new_current;
11655 if (current->IsCatchContext()) {
11656 Handle<String> name(String::cast(current->extension()));
11657 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11658 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011659 isolate->factory()->NewCatchContext(function,
11660 new_previous,
11661 name,
11662 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011663 } else if (current->IsBlockContext()) {
11664 Handle<SerializedScopeInfo> scope_info(
11665 SerializedScopeInfo::cast(current->extension()));
11666 new_current =
11667 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011668 // Copy context slots.
11669 int num_context_slots = scope_info->NumberOfContextSlots();
11670 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11671 new_current->set(i, current->get(i));
11672 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011673 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011674 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011675 Handle<JSObject> extension(JSObject::cast(current->extension()));
11676 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011677 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011678 }
11679 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011680}
11681
11682
11683// Helper function to find or create the arguments object for
11684// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685static Handle<Object> GetArgumentsObject(Isolate* isolate,
11686 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011687 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011688 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011689 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 const ScopeInfo<>* sinfo,
11691 Handle<Context> function_context) {
11692 // Try to find the value of 'arguments' to pass as parameter. If it is not
11693 // found (that is the debugged function does not reference 'arguments' and
11694 // does not support eval) then create an 'arguments' object.
11695 int index;
11696 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700 }
11701 }
11702
11703 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11705 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011706 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011707 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011708 }
11709 }
11710
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011711 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11712
11713 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 Handle<JSObject> arguments =
11715 isolate->factory()->NewArgumentsObject(function, length);
11716 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011717
11718 AssertNoAllocation no_gc;
11719 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011720 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011721 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011723 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724 return arguments;
11725}
11726
11727
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011728static const char kSourceStr[] =
11729 "(function(arguments,__source__){return eval(__source__);})";
11730
11731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011732// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011733// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734// extension part has all the parameters and locals of the function on the
11735// stack frame. A function which calls eval with the code to evaluate is then
11736// compiled in this context and called in this context. As this context
11737// replaces the context of the function on the stack frame a new (empty)
11738// function is created as well to be used as the closure for the context.
11739// This function and the context acts as replacements for the function on the
11740// stack frame presenting the same view of the values of parameters and
11741// local variables as if the piece of JavaScript was evaluated at the point
11742// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011743RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745
11746 // Check the execution state and decode arguments frame and source to be
11747 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011748 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011749 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011750 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11751 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011752 if (!maybe_check_result->ToObject(&check_result)) {
11753 return maybe_check_result;
11754 }
11755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011757 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11758 CONVERT_ARG_CHECKED(String, source, 3);
11759 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11760 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011761
11762 // Handle the processing of break.
11763 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764
11765 // Get the frame where the debugging is performed.
11766 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011767 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011768 JavaScriptFrame* frame = it.frame();
11769 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011770 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011771 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772
11773 // Traverse the saved contexts chain to find the active context for the
11774 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011775 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011776 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 save = save->prev();
11778 }
11779 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780 SaveContext savex(isolate);
11781 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782
11783 // Create the (empty) function replacing the function on the stack frame for
11784 // the purpose of evaluating in the context created below. It is important
11785 // that this function does not describe any parameters and local variables
11786 // in the context. If it does then this will cause problems with the lookup
11787 // in Context::Lookup, where context slots for parameters and local variables
11788 // are looked at before the extension object.
11789 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11791 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011792 go_between->set_context(function->context());
11793#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011794 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011795 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11796 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11797#endif
11798
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011799 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011800 Handle<JSObject> local_scope = MaterializeLocalScope(
11801 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011802 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803
11804 // Allocate a new context for the debug evaluation and set the extension
11805 // object build.
11806 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11808 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011809 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011810 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011811 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011812 Handle<Context> function_context;
11813 // Get the function's context if it has one.
11814 if (scope_info->HasHeapAllocatedLocals()) {
11815 function_context = Handle<Context>(frame_context->declaration_context());
11816 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011817 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011819 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011820 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011821 context =
11822 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011823 }
11824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011825 // Wrap the evaluation statement in a new function compiled in the newly
11826 // created context. The function has one parameter which has to be called
11827 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011828 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 isolate->factory()->NewStringFromAscii(
11833 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011834
11835 // Currently, the eval code will be executed in non-strict mode,
11836 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011837 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011838 Compiler::CompileEval(function_source,
11839 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011840 context->IsGlobalContext(),
11841 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011842 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845
11846 // Invoke the result of the compilation to get the evaluation function.
11847 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849 Handle<Object> evaluation_function =
11850 Execution::Call(compiled_function, receiver, 0, NULL,
11851 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011852 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011854 Handle<Object> arguments = GetArgumentsObject(isolate,
11855 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011857 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858
11859 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011860 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011862 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11863 receiver,
11864 ARRAY_SIZE(argv),
11865 argv,
11866 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011867 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011868
11869 // Skip the global proxy as it has no properties and always delegates to the
11870 // real global object.
11871 if (result->IsJSGlobalProxy()) {
11872 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11873 }
11874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011875 return *result;
11876}
11877
11878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011879RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881
11882 // Check the execution state and decode arguments frame and source to be
11883 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011884 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011885 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011886 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11887 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011888 if (!maybe_check_result->ToObject(&check_result)) {
11889 return maybe_check_result;
11890 }
11891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011893 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011894 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011895
11896 // Handle the processing of break.
11897 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011898
11899 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011901 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903 top = top->prev();
11904 }
11905 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011906 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 }
11908
11909 // Get the global context now set to the top context from before the
11910 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011913 bool is_global = true;
11914
11915 if (additional_context->IsJSObject()) {
11916 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11918 isolate->factory()->empty_string(),
11919 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011920 go_between->set_context(*context);
11921 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 isolate->factory()->NewFunctionContext(
11923 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011924 context->set_extension(JSObject::cast(*additional_context));
11925 is_global = false;
11926 }
11927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011929 // Currently, the eval code will be executed in non-strict mode,
11930 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011931 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011932 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011933 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011935 Handle<JSFunction>(
11936 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11937 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938
11939 // Invoke the result of the compilation to get the evaluation function.
11940 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 Handle<Object> result =
11943 Execution::Call(compiled_function, receiver, 0, NULL,
11944 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011945 // Clear the oneshot breakpoints so that the debugger does not step further.
11946 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011947 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 return *result;
11949}
11950
11951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011952RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011954 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011956 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011957 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958
11959 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011960 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011961 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11962 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11963 // because using
11964 // instances->set(i, *GetScriptWrapper(script))
11965 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11966 // already have deferenced the instances handle.
11967 Handle<JSValue> wrapper = GetScriptWrapper(script);
11968 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 }
11970
11971 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011972 Handle<JSObject> result =
11973 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011974 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 return *result;
11976}
11977
11978
11979// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011980static int DebugReferencedBy(HeapIterator* iterator,
11981 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011982 Object* instance_filter, int max_references,
11983 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984 JSFunction* arguments_function) {
11985 NoHandleAllocation ha;
11986 AssertNoAllocation no_alloc;
11987
11988 // Iterate the heap.
11989 int count = 0;
11990 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011991 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011992 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011993 (max_references == 0 || count < max_references)) {
11994 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995 if (heap_obj->IsJSObject()) {
11996 // Skip context extension objects and argument arrays as these are
11997 // checked in the context of functions using them.
11998 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011999 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012000 obj->map()->constructor() == arguments_function) {
12001 continue;
12002 }
12003
12004 // Check if the JS object has a reference to the object looked for.
12005 if (obj->ReferencesObject(target)) {
12006 // Check instance filter if supplied. This is normally used to avoid
12007 // references from mirror objects (see Runtime_IsInPrototypeChain).
12008 if (!instance_filter->IsUndefined()) {
12009 Object* V = obj;
12010 while (true) {
12011 Object* prototype = V->GetPrototype();
12012 if (prototype->IsNull()) {
12013 break;
12014 }
12015 if (instance_filter == prototype) {
12016 obj = NULL; // Don't add this object.
12017 break;
12018 }
12019 V = prototype;
12020 }
12021 }
12022
12023 if (obj != NULL) {
12024 // Valid reference found add to instance array if supplied an update
12025 // count.
12026 if (instances != NULL && count < instances_size) {
12027 instances->set(count, obj);
12028 }
12029 last = obj;
12030 count++;
12031 }
12032 }
12033 }
12034 }
12035
12036 // Check for circular reference only. This can happen when the object is only
12037 // referenced from mirrors and has a circular reference in which case the
12038 // object is not really alive and would have been garbage collected if not
12039 // referenced from the mirror.
12040 if (count == 1 && last == target) {
12041 count = 0;
12042 }
12043
12044 // Return the number of referencing objects found.
12045 return count;
12046}
12047
12048
12049// Scan the heap for objects with direct references to an object
12050// args[0]: the object to find references to
12051// args[1]: constructor function for instances to exclude (Mirror)
12052// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012053RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054 ASSERT(args.length() == 3);
12055
12056 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012057 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12058 // The heap iterator reserves the right to do a GC to make the heap iterable.
12059 // Due to the GC above we know it won't need to do that, but it seems cleaner
12060 // to get the heap iterator constructed before we start having unprotected
12061 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062
12063 // Check parameters.
12064 CONVERT_CHECKED(JSObject, target, args[0]);
12065 Object* instance_filter = args[1];
12066 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12067 instance_filter->IsJSObject());
12068 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12069 RUNTIME_ASSERT(max_references >= 0);
12070
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012071
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012073 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012074 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075 JSFunction* arguments_function =
12076 JSFunction::cast(arguments_boilerplate->map()->constructor());
12077
12078 // Get the number of referencing objects.
12079 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012080 HeapIterator heap_iterator;
12081 count = DebugReferencedBy(&heap_iterator,
12082 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012083 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084
12085 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012086 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012087 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012088 if (!maybe_object->ToObject(&object)) return maybe_object;
12089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090 FixedArray* instances = FixedArray::cast(object);
12091
12092 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012093 // AllocateFixedArray above does not make the heap non-iterable.
12094 ASSERT(HEAP->IsHeapIterable());
12095 HeapIterator heap_iterator2;
12096 count = DebugReferencedBy(&heap_iterator2,
12097 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012098 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
12100 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012101 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012102 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012103 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012104 if (!maybe_result->ToObject(&result)) return maybe_result;
12105 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106}
12107
12108
12109// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012110static int DebugConstructedBy(HeapIterator* iterator,
12111 JSFunction* constructor,
12112 int max_references,
12113 FixedArray* instances,
12114 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 AssertNoAllocation no_alloc;
12116
12117 // Iterate the heap.
12118 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012119 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012120 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 (max_references == 0 || count < max_references)) {
12122 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 if (heap_obj->IsJSObject()) {
12124 JSObject* obj = JSObject::cast(heap_obj);
12125 if (obj->map()->constructor() == constructor) {
12126 // Valid reference found add to instance array if supplied an update
12127 // count.
12128 if (instances != NULL && count < instances_size) {
12129 instances->set(count, obj);
12130 }
12131 count++;
12132 }
12133 }
12134 }
12135
12136 // Return the number of referencing objects found.
12137 return count;
12138}
12139
12140
12141// Scan the heap for objects constructed by a specific function.
12142// args[0]: the constructor to find instances of
12143// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012144RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012145 ASSERT(args.length() == 2);
12146
12147 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012148 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149
12150 // Check parameters.
12151 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12152 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12153 RUNTIME_ASSERT(max_references >= 0);
12154
12155 // Get the number of referencing objects.
12156 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012157 HeapIterator heap_iterator;
12158 count = DebugConstructedBy(&heap_iterator,
12159 constructor,
12160 max_references,
12161 NULL,
12162 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163
12164 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012165 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012166 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012167 if (!maybe_object->ToObject(&object)) return maybe_object;
12168 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169 FixedArray* instances = FixedArray::cast(object);
12170
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012171 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012173 HeapIterator heap_iterator2;
12174 count = DebugConstructedBy(&heap_iterator2,
12175 constructor,
12176 max_references,
12177 instances,
12178 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179
12180 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012181 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12183 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012184 if (!maybe_result->ToObject(&result)) return maybe_result;
12185 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012186 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012187}
12188
12189
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012190// Find the effective prototype object as returned by __proto__.
12191// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012192RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193 ASSERT(args.length() == 1);
12194
12195 CONVERT_CHECKED(JSObject, obj, args[0]);
12196
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012197 // Use the __proto__ accessor.
12198 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199}
12200
12201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012202RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012203 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206}
12207
12208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012209RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012210#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012211 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012212 ASSERT(args.length() == 1);
12213 // Get the function and make sure it is compiled.
12214 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012215 Handle<SharedFunctionInfo> shared(func->shared());
12216 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012217 return Failure::Exception();
12218 }
12219 func->code()->PrintLn();
12220#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012222}
ager@chromium.org9085a012009-05-11 19:22:57 +000012223
12224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012225RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012226#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012227 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012228 ASSERT(args.length() == 1);
12229 // Get the function and make sure it is compiled.
12230 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012231 Handle<SharedFunctionInfo> shared(func->shared());
12232 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012233 return Failure::Exception();
12234 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012235 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012236#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012238}
12239
12240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012241RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012242 NoHandleAllocation ha;
12243 ASSERT(args.length() == 1);
12244
12245 CONVERT_CHECKED(JSFunction, f, args[0]);
12246 return f->shared()->inferred_name();
12247}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012248
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012249
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012250static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12251 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012253 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012254 int counter = 0;
12255 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012256 for (HeapObject* obj = iterator->next();
12257 obj != NULL;
12258 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012259 ASSERT(obj != NULL);
12260 if (!obj->IsSharedFunctionInfo()) {
12261 continue;
12262 }
12263 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12264 if (shared->script() != script) {
12265 continue;
12266 }
12267 if (counter < buffer_size) {
12268 buffer->set(counter, shared);
12269 }
12270 counter++;
12271 }
12272 return counter;
12273}
12274
12275// For a script finds all SharedFunctionInfo's in the heap that points
12276// to this script. Returns JSArray of SharedFunctionInfo wrapped
12277// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012278RUNTIME_FUNCTION(MaybeObject*,
12279 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012280 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012282 CONVERT_CHECKED(JSValue, script_value, args[0]);
12283
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012285 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12286
12287 const int kBufferSize = 32;
12288
12289 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012291 int number;
12292 {
12293 isolate->heap()->EnsureHeapIsIterable();
12294 AssertNoAllocation no_allocations;
12295 HeapIterator heap_iterator;
12296 Script* scr = *script;
12297 FixedArray* arr = *array;
12298 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12299 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012300 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012302 isolate->heap()->EnsureHeapIsIterable();
12303 AssertNoAllocation no_allocations;
12304 HeapIterator heap_iterator;
12305 Script* scr = *script;
12306 FixedArray* arr = *array;
12307 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012308 }
12309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012311 result->set_length(Smi::FromInt(number));
12312
12313 LiveEdit::WrapSharedFunctionInfos(result);
12314
12315 return *result;
12316}
12317
12318// For a script calculates compilation information about all its functions.
12319// The script source is explicitly specified by the second argument.
12320// The source of the actual script is not used, however it is important that
12321// all generated code keeps references to this particular instance of script.
12322// Returns a JSArray of compilation infos. The array is ordered so that
12323// each function with all its descendant is always stored in a continues range
12324// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012325RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012326 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012327 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012328 CONVERT_CHECKED(JSValue, script, args[0]);
12329 CONVERT_ARG_CHECKED(String, source, 1);
12330 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12331
12332 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012334 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012335 return Failure::Exception();
12336 }
12337
12338 return result;
12339}
12340
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012341// Changes the source of the script to a new_source.
12342// If old_script_name is provided (i.e. is a String), also creates a copy of
12343// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012344RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012345 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012346 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012347 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12348 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012349 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012350
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012351 CONVERT_CHECKED(Script, original_script_pointer,
12352 original_script_value->value());
12353 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012354
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012355 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12356 new_source,
12357 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012358
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012359 if (old_script->IsScript()) {
12360 Handle<Script> script_handle(Script::cast(old_script));
12361 return *(GetScriptWrapper(script_handle));
12362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012364 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012365}
12366
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012368RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012369 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012371 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12372 return LiveEdit::FunctionSourceUpdated(shared_info);
12373}
12374
12375
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012376// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012377RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012378 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012380 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12381 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12382
ager@chromium.orgac091b72010-05-05 07:34:42 +000012383 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012384}
12385
12386// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012387RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012388 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012389 HandleScope scope(isolate);
12390 Handle<Object> function_object(args[0], isolate);
12391 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012392
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012393 if (function_object->IsJSValue()) {
12394 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12395 if (script_object->IsJSValue()) {
12396 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012397 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012398 }
12399
12400 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12401 } else {
12402 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12403 // and we check it in this function.
12404 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012406 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012407}
12408
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012409
12410// In a code of a parent function replaces original function as embedded object
12411// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012412RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012413 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012414 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012415
12416 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12417 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12418 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12419
12420 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12421 subst_wrapper);
12422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012423 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012424}
12425
12426
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012427// Updates positions of a shared function info (first parameter) according
12428// to script source change. Text change is described in second parameter as
12429// array of groups of 3 numbers:
12430// (change_begin, change_end, change_end_new_position).
12431// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012432RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012433 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012434 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12436 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12437
ager@chromium.orgac091b72010-05-05 07:34:42 +000012438 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439}
12440
12441
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012442// For array of SharedFunctionInfo's (each wrapped in JSValue)
12443// checks that none of them have activations on stacks (of any thread).
12444// Returns array of the same length with corresponding results of
12445// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012446RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012447 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012448 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012449 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012450 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012451
ager@chromium.org357bf652010-04-12 11:30:10 +000012452 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012453}
12454
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012455// Compares 2 strings line-by-line, then token-wise and returns diff in form
12456// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12457// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012458RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012459 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012460 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012461 CONVERT_ARG_CHECKED(String, s1, 0);
12462 CONVERT_ARG_CHECKED(String, s2, 1);
12463
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012464 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012465}
12466
12467
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012468// A testing entry. Returns statement position which is the closest to
12469// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012470RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012471 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012472 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012473 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12474 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012476 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012477
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012478 if (code->kind() != Code::FUNCTION &&
12479 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012481 }
12482
12483 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012484 int closest_pc = 0;
12485 int distance = kMaxInt;
12486 while (!it.done()) {
12487 int statement_position = static_cast<int>(it.rinfo()->data());
12488 // Check if this break point is closer that what was previously found.
12489 if (source_position <= statement_position &&
12490 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012491 closest_pc =
12492 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012493 distance = statement_position - source_position;
12494 // Check whether we can't get any closer.
12495 if (distance == 0) break;
12496 }
12497 it.next();
12498 }
12499
12500 return Smi::FromInt(closest_pc);
12501}
12502
12503
ager@chromium.org357bf652010-04-12 11:30:10 +000012504// Calls specified function with or without entering the debugger.
12505// This is used in unit tests to run code as if debugger is entered or simply
12506// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012507RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012508 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012509 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012510 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12511 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12512
12513 Handle<Object> result;
12514 bool pending_exception;
12515 {
12516 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012517 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012518 &pending_exception);
12519 } else {
12520 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012521 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012522 &pending_exception);
12523 }
12524 }
12525 if (!pending_exception) {
12526 return *result;
12527 } else {
12528 return Failure::Exception();
12529 }
12530}
12531
12532
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012533// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012534RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012535 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012536 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012537 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12538 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012539 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012540}
12541
12542
12543// Performs a GC.
12544// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012545RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 isolate->heap()->CollectAllGarbage(true);
12547 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012548}
12549
12550
12551// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012553 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012554 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012556 }
12557 return Smi::FromInt(usage);
12558}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012559
12560
12561// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012562RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012563#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012565#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012566 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012567#endif
12568}
12569
12570
12571// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012572RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012573#ifdef LIVE_OBJECT_LIST
12574 return LiveObjectList::Capture();
12575#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012576 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012577#endif
12578}
12579
12580
12581// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012582RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012583#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012584 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012585 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012586 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012587#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012589#endif
12590}
12591
12592
12593// Generates the response to a debugger request for a dump of the objects
12594// contained in the difference between the captured live object lists
12595// specified by id1 and id2.
12596// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12597// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012598RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012599#ifdef LIVE_OBJECT_LIST
12600 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012601 CONVERT_SMI_ARG_CHECKED(id1, 0);
12602 CONVERT_SMI_ARG_CHECKED(id2, 1);
12603 CONVERT_SMI_ARG_CHECKED(start, 2);
12604 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012605 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12606 EnterDebugger enter_debugger;
12607 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12608#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012609 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012610#endif
12611}
12612
12613
12614// Gets the specified object as requested by the debugger.
12615// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012616RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012617#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012618 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012619 Object* result = LiveObjectList::GetObj(obj_id);
12620 return result;
12621#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012623#endif
12624}
12625
12626
12627// Gets the obj id for the specified address if valid.
12628// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012629RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012630#ifdef LIVE_OBJECT_LIST
12631 HandleScope scope;
12632 CONVERT_ARG_CHECKED(String, address, 0);
12633 Object* result = LiveObjectList::GetObjId(address);
12634 return result;
12635#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012637#endif
12638}
12639
12640
12641// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012642RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012643#ifdef LIVE_OBJECT_LIST
12644 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012645 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012646 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12647 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12648 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12649 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12650 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12651
12652 Handle<JSObject> instance_filter;
12653 if (args[1]->IsJSObject()) {
12654 instance_filter = args.at<JSObject>(1);
12655 }
12656 bool verbose = false;
12657 if (args[2]->IsBoolean()) {
12658 verbose = args[2]->IsTrue();
12659 }
12660 int start = 0;
12661 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012662 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012663 }
12664 int limit = Smi::kMaxValue;
12665 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012666 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012667 }
12668
12669 return LiveObjectList::GetObjRetainers(obj_id,
12670 instance_filter,
12671 verbose,
12672 start,
12673 limit,
12674 filter_obj);
12675#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012677#endif
12678}
12679
12680
12681// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012683#ifdef LIVE_OBJECT_LIST
12684 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012685 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12686 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012687 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12688
12689 Handle<JSObject> instance_filter;
12690 if (args[2]->IsJSObject()) {
12691 instance_filter = args.at<JSObject>(2);
12692 }
12693
12694 Object* result =
12695 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12696 return result;
12697#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012698 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012699#endif
12700}
12701
12702
12703// Generates the response to a debugger request for a list of all
12704// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012705RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012706#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012707 CONVERT_SMI_ARG_CHECKED(start, 0);
12708 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012709 return LiveObjectList::Info(start, count);
12710#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012711 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#endif
12713}
12714
12715
12716// Gets a dump of the specified object as requested by the debugger.
12717// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012718RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012719#ifdef LIVE_OBJECT_LIST
12720 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012721 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012722 Object* result = LiveObjectList::PrintObj(obj_id);
12723 return result;
12724#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012725 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012726#endif
12727}
12728
12729
12730// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012731RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012732#ifdef LIVE_OBJECT_LIST
12733 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012734 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012735#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012737#endif
12738}
12739
12740
12741// Generates the response to a debugger request for a summary of the types
12742// of objects in the difference between the captured live object lists
12743// specified by id1 and id2.
12744// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12745// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012746RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012747#ifdef LIVE_OBJECT_LIST
12748 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012749 CONVERT_SMI_ARG_CHECKED(id1, 0);
12750 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012751 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12752
12753 EnterDebugger enter_debugger;
12754 return LiveObjectList::Summarize(id1, id2, filter_obj);
12755#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012757#endif
12758}
12759
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012760#endif // ENABLE_DEBUGGER_SUPPORT
12761
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012763RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012764 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012765 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012767}
12768
12769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012770RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012771 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012772 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012774}
12775
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012777// Finds the script object from the script data. NOTE: This operation uses
12778// heap traversal to find the function generated for the source position
12779// for the requested break point. For lazily compiled functions several heap
12780// traversals might be required rendering this operation as a rather slow
12781// operation. However for setting break points which is normally done through
12782// some kind of user interaction the performance is not crucial.
12783static Handle<Object> Runtime_GetScriptFromScriptName(
12784 Handle<String> script_name) {
12785 // Scan the heap for Script objects to find the script with the requested
12786 // script data.
12787 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012788 script_name->GetHeap()->EnsureHeapIsIterable();
12789 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012790 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012791 HeapObject* obj = NULL;
12792 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012793 // If a script is found check if it has the script data requested.
12794 if (obj->IsScript()) {
12795 if (Script::cast(obj)->name()->IsString()) {
12796 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12797 script = Handle<Script>(Script::cast(obj));
12798 }
12799 }
12800 }
12801 }
12802
12803 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012804 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012805
12806 // Return the script found.
12807 return GetScriptWrapper(script);
12808}
12809
12810
12811// Get the script object from script data. NOTE: Regarding performance
12812// see the NOTE for GetScriptFromScriptData.
12813// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012814RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012816
12817 ASSERT(args.length() == 1);
12818
12819 CONVERT_CHECKED(String, script_name, args[0]);
12820
12821 // Find the requested script.
12822 Handle<Object> result =
12823 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12824 return *result;
12825}
12826
12827
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012828// Determines whether the given stack frame should be displayed in
12829// a stack trace. The caller is the error constructor that asked
12830// for the stack trace to be collected. The first time a construct
12831// call to this function is encountered it is skipped. The seen_caller
12832// in/out parameter is used to remember if the caller has been seen
12833// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012834static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12835 Object* caller,
12836 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012837 // Only display JS frames.
12838 if (!raw_frame->is_java_script())
12839 return false;
12840 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12841 Object* raw_fun = frame->function();
12842 // Not sure when this can happen but skip it just in case.
12843 if (!raw_fun->IsJSFunction())
12844 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012845 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012846 *seen_caller = true;
12847 return false;
12848 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012849 // Skip all frames until we've seen the caller.
12850 if (!(*seen_caller)) return false;
12851 // Also, skip the most obvious builtin calls. We recognize builtins
12852 // as (1) functions called with the builtins object as the receiver and
12853 // as (2) functions from native scripts called with undefined as the
12854 // receiver (direct calls to helper functions in the builtins
12855 // code). Some builtin calls (such as Number.ADD which is invoked
12856 // using 'call') are very difficult to recognize so we're leaving
12857 // them in for now.
12858 if (frame->receiver()->IsJSBuiltinsObject()) {
12859 return false;
12860 }
12861 JSFunction* fun = JSFunction::cast(raw_fun);
12862 Object* raw_script = fun->shared()->script();
12863 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12864 int script_type = Script::cast(raw_script)->type()->value();
12865 return script_type != Script::TYPE_NATIVE;
12866 }
12867 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012868}
12869
12870
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012871// Collect the raw data for a stack trace. Returns an array of 4
12872// element segments each containing a receiver, function, code and
12873// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012874RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012875 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012876 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012877 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 HandleScope scope(isolate);
12880 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012881
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012882 limit = Max(limit, 0); // Ensure that limit is not negative.
12883 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012884 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012886
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012887 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012888 // If the caller parameter is a function we skip frames until we're
12889 // under it before starting to collect.
12890 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012891 int cursor = 0;
12892 int frames_seen = 0;
12893 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012894 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012895 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012896 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012897 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012898 // Set initial size to the maximum inlining level + 1 for the outermost
12899 // function.
12900 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012901 frame->Summarize(&frames);
12902 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012903 if (cursor + 4 > elements->length()) {
12904 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12905 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012907 for (int i = 0; i < cursor; i++) {
12908 new_elements->set(i, elements->get(i));
12909 }
12910 elements = new_elements;
12911 }
12912 ASSERT(cursor + 4 <= elements->length());
12913
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012914 Handle<Object> recv = frames[i].receiver();
12915 Handle<JSFunction> fun = frames[i].function();
12916 Handle<Code> code = frames[i].code();
12917 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012918 elements->set(cursor++, *recv);
12919 elements->set(cursor++, *fun);
12920 elements->set(cursor++, *code);
12921 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012922 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012923 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012924 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012925 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012927 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012928 return *result;
12929}
12930
12931
ager@chromium.org3811b432009-10-28 14:53:37 +000012932// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012933RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012934 ASSERT_EQ(args.length(), 0);
12935
12936 NoHandleAllocation ha;
12937
12938 const char* version_string = v8::V8::GetVersion();
12939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012940 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12941 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012942}
12943
12944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012945RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012946 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012947 OS::PrintError("abort: %s\n",
12948 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012950 OS::Abort();
12951 UNREACHABLE();
12952 return NULL;
12953}
12954
12955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012956RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012957 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012958 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012959 Object* key = args[1];
12960
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012961 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012962 Object* o = cache->get(finger_index);
12963 if (o == key) {
12964 // The fastest case: hit the same place again.
12965 return cache->get(finger_index + 1);
12966 }
12967
12968 for (int i = finger_index - 2;
12969 i >= JSFunctionResultCache::kEntriesIndex;
12970 i -= 2) {
12971 o = cache->get(i);
12972 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012973 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012974 return cache->get(i + 1);
12975 }
12976 }
12977
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012978 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012979 ASSERT(size <= cache->length());
12980
12981 for (int i = size - 2; i > finger_index; i -= 2) {
12982 o = cache->get(i);
12983 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012984 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012985 return cache->get(i + 1);
12986 }
12987 }
12988
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012989 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012990 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012991
12992 Handle<JSFunctionResultCache> cache_handle(cache);
12993 Handle<Object> key_handle(key);
12994 Handle<Object> value;
12995 {
12996 Handle<JSFunction> factory(JSFunction::cast(
12997 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12998 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013000 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013001 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013002 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013003 value = Execution::Call(factory,
13004 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013005 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013006 argv,
13007 &pending_exception);
13008 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013009 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013010
13011#ifdef DEBUG
13012 cache_handle->JSFunctionResultCacheVerify();
13013#endif
13014
13015 // Function invocation may have cleared the cache. Reread all the data.
13016 finger_index = cache_handle->finger_index();
13017 size = cache_handle->size();
13018
13019 // If we have spare room, put new data into it, otherwise evict post finger
13020 // entry which is likely to be the least recently used.
13021 int index = -1;
13022 if (size < cache_handle->length()) {
13023 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13024 index = size;
13025 } else {
13026 index = finger_index + JSFunctionResultCache::kEntrySize;
13027 if (index == cache_handle->length()) {
13028 index = JSFunctionResultCache::kEntriesIndex;
13029 }
13030 }
13031
13032 ASSERT(index % 2 == 0);
13033 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13034 ASSERT(index < cache_handle->length());
13035
13036 cache_handle->set(index, *key_handle);
13037 cache_handle->set(index + 1, *value);
13038 cache_handle->set_finger_index(index);
13039
13040#ifdef DEBUG
13041 cache_handle->JSFunctionResultCacheVerify();
13042#endif
13043
13044 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013045}
13046
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013048RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013050 CONVERT_ARG_CHECKED(String, type, 0);
13051 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013052 return *isolate->factory()->NewJSMessageObject(
13053 type,
13054 arguments,
13055 0,
13056 0,
13057 isolate->factory()->undefined_value(),
13058 isolate->factory()->undefined_value(),
13059 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013060}
13061
13062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013063RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013064 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13065 return message->type();
13066}
13067
13068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013069RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013070 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13071 return message->arguments();
13072}
13073
13074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013075RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013076 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13077 return Smi::FromInt(message->start_position());
13078}
13079
13080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013081RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013082 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13083 return message->script();
13084}
13085
13086
kasper.lund44510672008-07-25 07:37:58 +000013087#ifdef DEBUG
13088// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13089// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013090RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013091 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013093#define COUNT_ENTRY(Name, argc, ressize) + 1
13094 int entry_count = 0
13095 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13096 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13097 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13098#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013099 Factory* factory = isolate->factory();
13100 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013101 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013102 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013103#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013104 { \
13105 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013106 Handle<String> name; \
13107 /* Inline runtime functions have an underscore in front of the name. */ \
13108 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013109 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013110 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13111 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013112 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013113 Vector<const char>(#Name, StrLength(#Name))); \
13114 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013115 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013116 pair_elements->set(0, *name); \
13117 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013118 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013119 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013120 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013121 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013122 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013123 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013124 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013125 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013126#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013127 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013128 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013129 return *result;
13130}
kasper.lund44510672008-07-25 07:37:58 +000013131#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013132
13133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013134RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013135 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013136 CONVERT_CHECKED(String, format, args[0]);
13137 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013138 String::FlatContent format_content = format->GetFlatContent();
13139 RUNTIME_ASSERT(format_content.IsAscii());
13140 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013141 LOGGER->LogRuntime(chars, elms);
13142 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013143}
13144
13145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013146RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013147 UNREACHABLE(); // implemented as macro in the parser
13148 return NULL;
13149}
13150
13151
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013152#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13153 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13154 CONVERT_CHECKED(JSObject, obj, args[0]); \
13155 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13156 }
13157
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013158ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013159ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13160ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13161ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13162ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13163ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13164ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13165ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13166ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13167ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13168ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13169ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13170ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13171ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13172
13173#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013175// ----------------------------------------------------------------------------
13176// Implementation of Runtime
13177
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013178#define F(name, number_of_args, result_size) \
13179 { Runtime::k##name, Runtime::RUNTIME, #name, \
13180 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013181
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013182
13183#define I(name, number_of_args, result_size) \
13184 { Runtime::kInline##name, Runtime::INLINE, \
13185 "_" #name, NULL, number_of_args, result_size },
13186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013187static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013188 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013189 INLINE_FUNCTION_LIST(I)
13190 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013191};
13192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013194MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13195 Object* dictionary) {
13196 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013197 ASSERT(dictionary != NULL);
13198 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13199 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013200 Object* name_symbol;
13201 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013202 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013203 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13204 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013205 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013206 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13207 String::cast(name_symbol),
13208 Smi::FromInt(i),
13209 PropertyDetails(NONE, NORMAL));
13210 if (!maybe_dictionary->ToObject(&dictionary)) {
13211 // Non-recoverable failure. Calling code must restart heap
13212 // initialization.
13213 return maybe_dictionary;
13214 }
13215 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013216 }
13217 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013218}
13219
13220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013221const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13222 Heap* heap = name->GetHeap();
13223 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013224 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013225 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013226 int function_index = Smi::cast(smi_index)->value();
13227 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013228 }
13229 return NULL;
13230}
13231
13232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013233const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013234 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13235}
13236
13237
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013238void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013239 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013240 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013241 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013242 if (isolate->heap()->new_space()->AddFreshPage()) {
13243 return;
13244 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013245 // Try to do a garbage collection; ignore it if it fails. The C
13246 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013247 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013248 } else {
13249 // Handle last resort GC and make sure to allow future allocations
13250 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013251 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013252 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013253 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013254}
13255
13256
13257} } // namespace v8::internal