blob: 5e96ef8e1c38cb77352c3a33d5169e5294582f53 [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"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
222 default:
223 UNREACHABLE();
224 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000225 }
226 return copy;
227}
228
229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000230RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000233}
234
235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000236RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239}
240
241
ager@chromium.org236ad962008-09-25 09:45:57 +0000242static Handle<Map> ComputeObjectLiteralMap(
243 Handle<Context> context,
244 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000245 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000246 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 int properties_length = constant_properties->length();
248 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000251 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000252 for (int p = 0; p != properties_length; p += 2) {
253 Object* key = constant_properties->get(p);
254 uint32_t element_index = 0;
255 if (key->IsSymbol()) {
256 number_of_symbol_keys++;
257 } else if (key->ToArrayIndex(&element_index)) {
258 // An index key does not require space in the property backing store.
259 number_of_properties--;
260 } else {
261 // Bail out as a non-symbol non-index key makes caching impossible.
262 // ASSERT to make sure that the if condition after the loop is false.
263 ASSERT(number_of_symbol_keys != number_of_properties);
264 break;
265 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000267 // If we only have symbols and array indices among keys then we can
268 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000270 if ((number_of_symbol_keys == number_of_properties) &&
271 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Handle<FixedArray> keys =
274 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 if (number_of_symbol_keys > 0) {
276 int index = 0;
277 for (int p = 0; p < properties_length; p += 2) {
278 Object* key = constant_properties->get(p);
279 if (key->IsSymbol()) {
280 keys->set(index++, key);
281 }
282 }
283 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000285 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 }
288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000289 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000291 Handle<Map>(context->object_function()->initial_map()),
292 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000293}
294
295
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298 Handle<FixedArray> literals,
299 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000300
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301
302static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000304 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000305 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 bool should_have_fast_elements,
307 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000308 // Get the global context from the literals array. This is the
309 // context in which the function was created and we use the object
310 // function from this context to create the object literal. We do
311 // not use the object function from the current global context
312 // because this might be the object function from another context
313 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 Handle<Context> context =
315 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 // In case we have function literals, we want the object to be in
318 // slow properties mode for now. We don't go in the map cache because
319 // maps with constant functions can't be shared if the functions are
320 // not the same (which is the common case).
321 bool is_result_from_cache = false;
322 Handle<Map> map = has_function_literal
323 ? Handle<Map>(context->object_function()->initial_map())
324 : ComputeObjectLiteralMap(context,
325 constant_properties,
326 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000329
330 // Normalize the elements of the boilerplate to save space if needed.
331 if (!should_have_fast_elements) NormalizeElements(boilerplate);
332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 // Add the constant properties to the boilerplate.
334 int length = constant_properties->length();
335 bool should_transform =
336 !is_result_from_cache && boilerplate->HasFastProperties();
337 if (should_transform || has_function_literal) {
338 // Normalize the properties of object to avoid n^2 behavior
339 // when extending the object multiple properties. Indicate the number of
340 // properties to be added.
341 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
342 }
343
344 for (int index = 0; index < length; index +=2) {
345 Handle<Object> key(constant_properties->get(index+0), isolate);
346 Handle<Object> value(constant_properties->get(index+1), isolate);
347 if (value->IsFixedArray()) {
348 // The value contains the constant_properties of a
349 // simple object or array literal.
350 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
351 value = CreateLiteralBoilerplate(isolate, literals, array);
352 if (value.is_null()) return value;
353 }
354 Handle<Object> result;
355 uint32_t element_index = 0;
356 if (key->IsSymbol()) {
357 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
358 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000359 result = SetOwnElement(boilerplate,
360 element_index,
361 value,
362 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000364 Handle<String> name(String::cast(*key));
365 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000366 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
367 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 } else if (key->ToArrayIndex(&element_index)) {
370 // Array index (uint32).
371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
375 } else {
376 // Non-uint32 number.
377 ASSERT(key->IsNumber());
378 double num = key->Number();
379 char arr[100];
380 Vector<char> buffer(arr, ARRAY_SIZE(arr));
381 const char* str = DoubleToCString(num, buffer);
382 Handle<String> name =
383 isolate->factory()->NewStringFromAscii(CStrVector(str));
384 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 // If setting the property on the boilerplate throws an
388 // exception, the exception is converted to an empty handle in
389 // the handle based operations. In that case, we need to
390 // convert back to an exception.
391 if (result.is_null()) return result;
392 }
393
394 // Transform to fast properties if necessary. For object literals with
395 // containing function literals we defer this operation until after all
396 // computed properties have been assigned so that we can generate
397 // constant function properties.
398 if (should_transform && !has_function_literal) {
399 TransformToFastProperties(boilerplate,
400 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000403 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000404}
405
406
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000409 Handle<FixedArray> literals,
410 Handle<FixedArray> elements) {
411 // Create the JSArray.
412 Handle<JSFunction> constructor(
413 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 const bool is_cow =
417 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000418 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420
421 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000422 if (is_cow) {
423#ifdef DEBUG
424 // Copy-on-write arrays must be shallow (and simple).
425 for (int i = 0; i < content->length(); i++) {
426 ASSERT(!content->get(i)->IsFixedArray());
427 }
428#endif
429 } else {
430 for (int i = 0; i < content->length(); i++) {
431 if (content->get(i)->IsFixedArray()) {
432 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
435 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000437 if (result.is_null()) return result;
438 content->set(i, *result);
439 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 }
441 }
442
443 // Set the elements.
444 Handle<JSArray>::cast(object)->SetContent(*content);
445 return object;
446}
447
448
449static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000451 Handle<FixedArray> literals,
452 Handle<FixedArray> array) {
453 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000455 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 return CreateObjectLiteralBoilerplate(isolate,
458 literals,
459 elements,
460 true,
461 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 return CreateObjectLiteralBoilerplate(isolate,
464 literals,
465 elements,
466 false,
467 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000470 default:
471 UNREACHABLE();
472 return Handle<Object>::null();
473 }
474}
475
476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000477RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000478 // Takes a FixedArray of elements containing the literal elements of
479 // the array literal and produces JSArray with those elements.
480 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000481 // which contains the context from which to get the Array function
482 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000484 ASSERT(args.length() == 3);
485 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000486 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 Handle<Object> object =
490 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000493 // Update the functions literal and return the boilerplate.
494 literals->set(literals_index, *object);
495 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000499RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000501 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000503 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000504 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000505 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000506 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
507 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000508
509 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000510 Handle<Object> boilerplate(literals->get(literals_index), isolate);
511 if (*boilerplate == isolate->heap()->undefined_value()) {
512 boilerplate = CreateObjectLiteralBoilerplate(isolate,
513 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 should_have_fast_elements,
516 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 if (boilerplate.is_null()) return Failure::Exception();
518 // Update the functions literal and return the boilerplate.
519 literals->set(literals_index, *boilerplate);
520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522}
523
524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000525RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000528 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000529 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000531 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
533 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534
535 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 Handle<Object> boilerplate(literals->get(literals_index), isolate);
537 if (*boilerplate == isolate->heap()->undefined_value()) {
538 boilerplate = CreateObjectLiteralBoilerplate(isolate,
539 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 should_have_fast_elements,
542 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 if (boilerplate.is_null()) return Failure::Exception();
544 // Update the functions literal and return the boilerplate.
545 literals->set(literals_index, *boilerplate);
546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548}
549
550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000551RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000553 ASSERT(args.length() == 3);
554 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
557
558 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 Handle<Object> boilerplate(literals->get(literals_index), isolate);
560 if (*boilerplate == isolate->heap()->undefined_value()) {
561 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000562 if (boilerplate.is_null()) return Failure::Exception();
563 // Update the functions literal and return the boilerplate.
564 literals->set(literals_index, *boilerplate);
565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572 ASSERT(args.length() == 3);
573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 if (boilerplate.is_null()) return Failure::Exception();
582 // Update the functions literal and return the boilerplate.
583 literals->set(literals_index, *boilerplate);
584 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000587 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
594 ASSERT(args.length() == 2);
595 Object* handler = args[0];
596 Object* prototype = args[1];
597 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000598 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
604 ASSERT(args.length() == 1);
605 Object* obj = args[0];
606 return obj->IsJSProxy()
607 ? isolate->heap()->true_value() : isolate->heap()->false_value();
608}
609
610
611RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
612 ASSERT(args.length() == 1);
613 CONVERT_CHECKED(JSProxy, proxy, args[0]);
614 return proxy->handler();
615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 NoHandleAllocation ha;
620 ASSERT(args.length() == 1);
621 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 return JSObject::cast(obj)->class_name();
624}
625
ager@chromium.org7c537e22008-10-16 08:43:32 +0000626
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000627RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
628 NoHandleAllocation ha;
629 ASSERT(args.length() == 1);
630 Object* obj = args[0];
631 obj = obj->GetPrototype();
632 while (obj->IsJSObject() &&
633 JSObject::cast(obj)->map()->is_hidden_prototype()) {
634 obj = obj->GetPrototype();
635 }
636 return obj;
637}
638
639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 NoHandleAllocation ha;
642 ASSERT(args.length() == 2);
643 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
644 Object* O = args[0];
645 Object* V = args[1];
646 while (true) {
647 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 if (prototype->IsNull()) return isolate->heap()->false_value();
649 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 V = prototype;
651 }
652}
653
654
ager@chromium.org9085a012009-05-11 19:22:57 +0000655// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000656RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000657 NoHandleAllocation ha;
658 ASSERT(args.length() == 2);
659 CONVERT_CHECKED(JSObject, jsobject, args[0]);
660 CONVERT_CHECKED(JSObject, proto, args[1]);
661
662 // Sanity checks. The old prototype (that we are replacing) could
663 // theoretically be null, but if it is not null then check that we
664 // didn't already install a hidden prototype here.
665 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
666 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
667 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
668
669 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000670 Object* map_or_failure;
671 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
672 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
673 return maybe_map_or_failure;
674 }
675 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 Map* new_proto_map = Map::cast(map_or_failure);
677
lrn@chromium.org303ada72010-10-27 09:33:13 +0000678 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
679 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
680 return maybe_map_or_failure;
681 }
682 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000683 Map* new_map = Map::cast(map_or_failure);
684
685 // Set proto's prototype to be the old prototype of the object.
686 new_proto_map->set_prototype(jsobject->GetPrototype());
687 proto->set_map(new_proto_map);
688 new_proto_map->set_is_hidden_prototype();
689
690 // Set the object's prototype to proto.
691 new_map->set_prototype(proto);
692 jsobject->set_map(new_map);
693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000694 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000695}
696
697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000698RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000700 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000701 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703}
704
705
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000706// Recursively traverses hidden prototypes if property is not found
707static void GetOwnPropertyImplementation(JSObject* obj,
708 String* name,
709 LookupResult* result) {
710 obj->LocalLookupRealNamedProperty(name, result);
711
712 if (!result->IsProperty()) {
713 Object* proto = obj->GetPrototype();
714 if (proto->IsJSObject() &&
715 JSObject::cast(proto)->map()->is_hidden_prototype())
716 GetOwnPropertyImplementation(JSObject::cast(proto),
717 name, result);
718 }
719}
720
721
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000722static bool CheckAccessException(LookupResult* result,
723 v8::AccessType access_type) {
724 if (result->type() == CALLBACKS) {
725 Object* callback = result->GetCallbackObject();
726 if (callback->IsAccessorInfo()) {
727 AccessorInfo* info = AccessorInfo::cast(callback);
728 bool can_access =
729 (access_type == v8::ACCESS_HAS &&
730 (info->all_can_read() || info->all_can_write())) ||
731 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
732 (access_type == v8::ACCESS_SET && info->all_can_write());
733 return can_access;
734 }
735 }
736
737 return false;
738}
739
740
741static bool CheckAccess(JSObject* obj,
742 String* name,
743 LookupResult* result,
744 v8::AccessType access_type) {
745 ASSERT(result->IsProperty());
746
747 JSObject* holder = result->holder();
748 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000750 while (true) {
751 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000752 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000753 // Access check callback denied the access, but some properties
754 // can have a special permissions which override callbacks descision
755 // (currently see v8::AccessControl).
756 break;
757 }
758
759 if (current == holder) {
760 return true;
761 }
762
763 current = JSObject::cast(current->GetPrototype());
764 }
765
766 // API callbacks can have per callback access exceptions.
767 switch (result->type()) {
768 case CALLBACKS: {
769 if (CheckAccessException(result, access_type)) {
770 return true;
771 }
772 break;
773 }
774 case INTERCEPTOR: {
775 // If the object has an interceptor, try real named properties.
776 // Overwrite the result to fetch the correct property later.
777 holder->LookupRealNamedProperty(name, result);
778 if (result->IsProperty()) {
779 if (CheckAccessException(result, access_type)) {
780 return true;
781 }
782 }
783 break;
784 }
785 default:
786 break;
787 }
788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000789 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000790 return false;
791}
792
793
794// TODO(1095): we should traverse hidden prototype hierachy as well.
795static bool CheckElementAccess(JSObject* obj,
796 uint32_t index,
797 v8::AccessType access_type) {
798 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000800 return false;
801 }
802
803 return true;
804}
805
806
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000807// Enumerator used as indices into the array returned from GetOwnProperty
808enum PropertyDescriptorIndices {
809 IS_ACCESSOR_INDEX,
810 VALUE_INDEX,
811 GETTER_INDEX,
812 SETTER_INDEX,
813 WRITABLE_INDEX,
814 ENUMERABLE_INDEX,
815 CONFIGURABLE_INDEX,
816 DESCRIPTOR_SIZE
817};
818
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000819// Returns an array with the property description:
820// if args[1] is not a property on args[0]
821// returns undefined
822// if args[1] is a data property on args[0]
823// [false, value, Writeable, Enumerable, Configurable]
824// if args[1] is an accessor on args[0]
825// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000826RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000827 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000828 Heap* heap = isolate->heap();
829 HandleScope scope(isolate);
830 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
831 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000832 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000833 CONVERT_ARG_CHECKED(JSObject, obj, 0);
834 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000835
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000836 // This could be an element.
837 uint32_t index;
838 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000839 switch (obj->HasLocalElement(index)) {
840 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000841 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000842
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000843 case JSObject::STRING_CHARACTER_ELEMENT: {
844 // Special handling of string objects according to ECMAScript 5
845 // 15.5.5.2. Note that this might be a string object with elements
846 // other than the actual string value. This is covered by the
847 // subsequent cases.
848 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
849 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000850 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 elms->set(WRITABLE_INDEX, heap->false_value());
855 elms->set(ENUMERABLE_INDEX, heap->false_value());
856 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000857 return *desc;
858 }
859
860 case JSObject::INTERCEPTED_ELEMENT:
861 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000862 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000863 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000865 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000866 elms->set(WRITABLE_INDEX, heap->true_value());
867 elms->set(ENUMERABLE_INDEX, heap->true_value());
868 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000869 return *desc;
870 }
871
872 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 Handle<JSObject> holder = obj;
874 if (obj->IsJSGlobalProxy()) {
875 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000877 ASSERT(proto->IsJSGlobalObject());
878 holder = Handle<JSObject>(JSObject::cast(proto));
879 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000880 FixedArray* elements = FixedArray::cast(holder->elements());
881 NumberDictionary* dictionary = NULL;
882 if (elements->map() == heap->non_strict_arguments_elements_map()) {
883 dictionary = NumberDictionary::cast(elements->get(1));
884 } else {
885 dictionary = NumberDictionary::cast(elements);
886 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000887 int entry = dictionary->FindEntry(index);
888 ASSERT(entry != NumberDictionary::kNotFound);
889 PropertyDetails details = dictionary->DetailsAt(entry);
890 switch (details.type()) {
891 case CALLBACKS: {
892 // This is an accessor property with getter and/or setter.
893 FixedArray* callbacks =
894 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000896 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
897 elms->set(GETTER_INDEX, callbacks->get(0));
898 }
899 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
900 elms->set(SETTER_INDEX, callbacks->get(1));
901 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 break;
903 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000904 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000907 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000908 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000909 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000911 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000912 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000913 default:
914 UNREACHABLE();
915 break;
916 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
918 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 return *desc;
920 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000921 }
922 }
923
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000924 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000925 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000926
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000927 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000929 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000930
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000931 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 }
934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
936 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000937
938 bool is_js_accessor = (result.type() == CALLBACKS) &&
939 (result.GetCallbackObject()->IsFixedArray());
940
941 if (is_js_accessor) {
942 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000944
945 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
946 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
947 elms->set(GETTER_INDEX, structure->get(0));
948 }
949 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
950 elms->set(SETTER_INDEX, structure->get(1));
951 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000952 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
954 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955
956 PropertyAttributes attrs;
957 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000958 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000959 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
960 if (!maybe_value->ToObject(&value)) return maybe_value;
961 }
962 elms->set(VALUE_INDEX, value);
963 }
964
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000965 return *desc;
966}
967
968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000969RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000970 ASSERT(args.length() == 1);
971 CONVERT_CHECKED(JSObject, obj, args[0]);
972 return obj->PreventExtensions();
973}
974
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000976RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000977 ASSERT(args.length() == 1);
978 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000979 if (obj->IsJSGlobalProxy()) {
980 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000982 ASSERT(proto->IsJSGlobalObject());
983 obj = JSObject::cast(proto);
984 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000985 return obj->map()->is_extensible() ? isolate->heap()->true_value()
986 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000987}
988
989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000990RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000993 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
994 CONVERT_ARG_CHECKED(String, pattern, 1);
995 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000996 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
997 if (result.is_null()) return Failure::Exception();
998 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999}
1000
1001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001002RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001005 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001010RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 ASSERT(args.length() == 1);
1012 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001013 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015}
1016
1017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 ASSERT(args.length() == 2);
1020 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001022 int index = field->value();
1023 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1024 InstanceType type = templ->map()->instance_type();
1025 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1026 type == OBJECT_TEMPLATE_INFO_TYPE);
1027 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001028 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001029 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1030 } else {
1031 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1032 }
1033 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034}
1035
1036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001037RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001038 ASSERT(args.length() == 1);
1039 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001040 Map* old_map = object->map();
1041 bool needs_access_checks = old_map->is_access_check_needed();
1042 if (needs_access_checks) {
1043 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001044 Object* new_map;
1045 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1046 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1047 }
ager@chromium.org32912102009-01-16 10:38:43 +00001048
1049 Map::cast(new_map)->set_is_access_check_needed(false);
1050 object->set_map(Map::cast(new_map));
1051 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 return needs_access_checks ? isolate->heap()->true_value()
1053 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001054}
1055
1056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001057RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001058 ASSERT(args.length() == 1);
1059 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001060 Map* old_map = object->map();
1061 if (!old_map->is_access_check_needed()) {
1062 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001063 Object* new_map;
1064 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1065 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1066 }
ager@chromium.org32912102009-01-16 10:38:43 +00001067
1068 Map::cast(new_map)->set_is_access_check_needed(true);
1069 object->set_map(Map::cast(new_map));
1070 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072}
1073
1074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075static Failure* ThrowRedeclarationError(Isolate* isolate,
1076 const char* type,
1077 Handle<String> name) {
1078 HandleScope scope(isolate);
1079 Handle<Object> type_handle =
1080 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 Handle<Object> args[2] = { type_handle, name };
1082 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1084 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085}
1086
1087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001088RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001089 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 HandleScope scope(isolate);
1091 Handle<GlobalObject> global = Handle<GlobalObject>(
1092 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093
ager@chromium.org3811b432009-10-28 14:53:37 +00001094 Handle<Context> context = args.at<Context>(0);
1095 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001096 bool is_eval = args.smi_at(2) == 1;
1097 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001098 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099
1100 // Compute the property attributes. According to ECMA-262, section
1101 // 13, page 71, the property must be read-only and
1102 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1103 // property as read-only, so we don't either.
1104 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 // Traverse the name/value pairs and set the properties.
1107 int length = pairs->length();
1108 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
1113 // We have to declare a global const property. To capture we only
1114 // assign to it when evaluating the assignment for "const x =
1115 // <expr>" the initial value is the hole.
1116 bool is_const_property = value->IsTheHole();
1117
1118 if (value->IsUndefined() || is_const_property) {
1119 // Lookup the property in the global object, and don't set the
1120 // value of the variable if the property is already there.
1121 LookupResult lookup;
1122 global->Lookup(*name, &lookup);
1123 if (lookup.IsProperty()) {
1124 // Determine if the property is local by comparing the holder
1125 // against the global object. The information will be used to
1126 // avoid throwing re-declaration errors when declaring
1127 // variables or constants that exist in the prototype chain.
1128 bool is_local = (*global == lookup.holder());
1129 // Get the property attributes and determine if the property is
1130 // read-only.
1131 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1132 bool is_read_only = (attributes & READ_ONLY) != 0;
1133 if (lookup.type() == INTERCEPTOR) {
1134 // If the interceptor says the property is there, we
1135 // just return undefined without overwriting the property.
1136 // Otherwise, we continue to setting the property.
1137 if (attributes != ABSENT) {
1138 // Check if the existing property conflicts with regards to const.
1139 if (is_local && (is_read_only || is_const_property)) {
1140 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 };
1143 // The property already exists without conflicting: Go to
1144 // the next declaration.
1145 continue;
1146 }
1147 // Fall-through and introduce the absent property by using
1148 // SetProperty.
1149 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001150 // For const properties, we treat a callback with this name
1151 // even in the prototype as a conflicting declaration.
1152 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001154 }
1155 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 if (is_local && (is_read_only || is_const_property)) {
1157 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001158 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 }
1160 // The property already exists without conflicting: Go to
1161 // the next declaration.
1162 continue;
1163 }
1164 }
1165 } else {
1166 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001167 Handle<SharedFunctionInfo> shared =
1168 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001170 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1171 context,
1172 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 value = function;
1174 }
1175
1176 LookupResult lookup;
1177 global->LocalLookup(*name, &lookup);
1178
1179 PropertyAttributes attributes = is_const_property
1180 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1181 : base;
1182
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001183 // There's a local property that we need to overwrite because
1184 // we're either declaring a function or there's an interceptor
1185 // that claims the property is absent.
1186 //
1187 // Check for conflicting re-declarations. We cannot have
1188 // conflicting types in case of intercepted properties because
1189 // they are absent.
1190 if (lookup.IsProperty() &&
1191 (lookup.type() != INTERCEPTOR) &&
1192 (lookup.IsReadOnly() || is_const_property)) {
1193 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001197 // Safari does not allow the invocation of callback setters for
1198 // function declarations. To mimic this behavior, we do not allow
1199 // the invocation of setters for function values. This makes a
1200 // difference for global functions with the same names as event
1201 // handlers such as "function onload() {}". Firefox does call the
1202 // onload setter in those case and Safari does not. We follow
1203 // Safari for compatibility.
1204 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001205 // Do not change DONT_DELETE to false from true.
1206 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1207 attributes = static_cast<PropertyAttributes>(
1208 attributes | (lookup.GetAttributes() & DONT_DELETE));
1209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 RETURN_IF_EMPTY_HANDLE(isolate,
1211 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001212 name,
1213 value,
1214 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 RETURN_IF_EMPTY_HANDLE(isolate,
1217 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001218 name,
1219 value,
1220 attributes,
1221 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001225 ASSERT(!isolate->has_pending_exception());
1226 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227}
1228
1229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001230RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001232 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233
ager@chromium.org7c537e22008-10-16 08:43:32 +00001234 CONVERT_ARG_CHECKED(Context, context, 0);
1235 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001236 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001237 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001240 // Declarations are always done in a function or global context.
1241 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242
1243 int index;
1244 PropertyAttributes attributes;
1245 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001246 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 context->Lookup(name, flags, &index, &attributes);
1248
1249 if (attributes != ABSENT) {
1250 // The name was declared before; check for conflicting
1251 // re-declarations: This is similar to the code in parser.cc in
1252 // the AstBuildingParser::Declare function.
1253 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1254 // Functions are not read-only.
1255 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1256 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 }
1259
1260 // Initialize it if necessary.
1261 if (*initial_value != NULL) {
1262 if (index >= 0) {
1263 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001264 // the function context or the arguments object.
1265 if (holder->IsContext()) {
1266 ASSERT(holder.is_identical_to(context));
1267 if (((attributes & READ_ONLY) == 0) ||
1268 context->get(index)->IsTheHole()) {
1269 context->set(index, *initial_value);
1270 }
1271 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001272 // The holder is an arguments object.
1273 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001274 Handle<Object> result = SetElement(arguments, index, initial_value,
1275 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001276 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278 } else {
1279 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001281 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001283 SetProperty(context_ext, name, initial_value,
1284 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001289 // The property is not in the function context. It needs to be
1290 // "declared" in the function context's extension context, or in the
1291 // global context.
1292 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001293 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001295 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001296 } else {
1297 // The function context's extension context does not exists - allocate
1298 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 context_ext = isolate->factory()->NewJSObject(
1300 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001301 // And store it in the extension slot.
1302 context->set_extension(*context_ext);
1303 }
1304 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
ager@chromium.org7c537e22008-10-16 08:43:32 +00001306 // Declare the property by setting it to the initial value if provided,
1307 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1308 // constant declarations).
1309 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001311 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001312 // Declaring a const context slot is a conflicting declaration if
1313 // there is a callback with that name in a prototype. It is
1314 // allowed to introduce const variables in
1315 // JSContextExtensionObjects. They are treated specially in
1316 // SetProperty and no setters are invoked for those since they are
1317 // not real JSObjects.
1318 if (initial_value->IsTheHole() &&
1319 !context_ext->IsJSContextExtensionObject()) {
1320 LookupResult lookup;
1321 context_ext->Lookup(*name, &lookup);
1322 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 }
1325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 RETURN_IF_EMPTY_HANDLE(isolate,
1327 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329 }
1330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332}
1333
1334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001335RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001337 // args[0] == name
1338 // args[1] == strict_mode
1339 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 // Determine if we need to assign to the variable if it already
1342 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1344 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001349 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
1352 // According to ECMA-262, section 12.2, page 62, the property must
1353 // not be deletable.
1354 PropertyAttributes attributes = DONT_DELETE;
1355
1356 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001357 // there, there is a property with this name in the prototype chain.
1358 // We follow Safari and Firefox behavior and only set the property
1359 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001360 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001361 // Note that objects can have hidden prototypes, so we need to traverse
1362 // the whole chain of hidden prototypes to do a 'local' lookup.
1363 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001365 while (true) {
1366 real_holder->LocalLookup(*name, &lookup);
1367 if (lookup.IsProperty()) {
1368 // Determine if this is a redeclaration of something read-only.
1369 if (lookup.IsReadOnly()) {
1370 // If we found readonly property on one of hidden prototypes,
1371 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 if (real_holder != isolate->context()->global()) break;
1373 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001374 }
1375
1376 // Determine if this is a redeclaration of an intercepted read-only
1377 // property and figure out if the property exists at all.
1378 bool found = true;
1379 PropertyType type = lookup.type();
1380 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 Handle<JSObject> holder(real_holder);
1383 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1384 real_holder = *holder;
1385 if (intercepted == ABSENT) {
1386 // The interceptor claims the property isn't there. We need to
1387 // make sure to introduce it.
1388 found = false;
1389 } else if ((intercepted & READ_ONLY) != 0) {
1390 // The property is present, but read-only. Since we're trying to
1391 // overwrite it with a variable declaration we must throw a
1392 // re-declaration error. However if we found readonly property
1393 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 if (real_holder != isolate->context()->global()) break;
1395 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001396 }
1397 }
1398
1399 if (found && !assign) {
1400 // The global property is there and we're not assigning any value
1401 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 }
1404
1405 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 return real_holder->SetProperty(
1408 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001409 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001410
1411 Object* proto = real_holder->GetPrototype();
1412 if (!proto->IsJSObject())
1413 break;
1414
1415 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1416 break;
1417
1418 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 }
1420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001422 if (assign) {
1423 return global->SetProperty(*name, args[2], attributes, strict_mode);
1424 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426}
1427
1428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001429RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 // All constants are declared with an initial value. The name
1431 // of the constant is the first argument and the initial value
1432 // is the second.
1433 RUNTIME_ASSERT(args.length() == 2);
1434 CONVERT_ARG_CHECKED(String, name, 0);
1435 Handle<Object> value = args.at<Object>(1);
1436
1437 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
1440 // According to ECMA-262, section 12.2, page 62, the property must
1441 // not be deletable. Since it's a const, it must be READ_ONLY too.
1442 PropertyAttributes attributes =
1443 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1444
1445 // Lookup the property locally in the global object. If it isn't
1446 // there, we add the property and take special precautions to always
1447 // add it as a local property even in case of callbacks in the
1448 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001449 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 LookupResult lookup;
1451 global->LocalLookup(*name, &lookup);
1452 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001453 return global->SetLocalPropertyIgnoreAttributes(*name,
1454 *value,
1455 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457
1458 // Determine if this is a redeclaration of something not
1459 // read-only. In case the result is hidden behind an interceptor we
1460 // need to ask it for the property attributes.
1461 if (!lookup.IsReadOnly()) {
1462 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 }
1465
1466 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1467
1468 // Throw re-declaration error if the intercepted property is present
1469 // but not read-only.
1470 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
1474 // Restore global object from context (in case of GC) and continue
1475 // with setting the value because the property is either absent or
1476 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 HandleScope handle_scope(isolate);
1478 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001480 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // property through an interceptor and only do it if it's
1482 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 RETURN_IF_EMPTY_HANDLE(isolate,
1485 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001486 name,
1487 value,
1488 attributes,
1489 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 return *value;
1491 }
1492
1493 // Set the value, but only we're assigning the initial value to a
1494 // constant. For now, we determine this by checking if the
1495 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001496 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 PropertyType type = lookup.type();
1498 if (type == FIELD) {
1499 FixedArray* properties = global->properties();
1500 int index = lookup.GetFieldIndex();
1501 if (properties->get(index)->IsTheHole()) {
1502 properties->set(index, *value);
1503 }
1504 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1506 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508 } else {
1509 // Ignore re-initialization of constants that have already been
1510 // assigned a function value.
1511 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1512 }
1513
1514 // Use the set value as the result of the operation.
1515 return *value;
1516}
1517
1518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001519RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 ASSERT(args.length() == 3);
1522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 ASSERT(!value->IsTheHole());
1525 CONVERT_ARG_CHECKED(Context, context, 1);
1526 Handle<String> name(String::cast(args[2]));
1527
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001528 // Initializations are always done in a function or global context.
1529 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530
1531 int index;
1532 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001534 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 context->Lookup(name, flags, &index, &attributes);
1536
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001537 // In most situations, the property introduced by the const
1538 // declaration should be present in the context extension object.
1539 // However, because declaration and initialization are separate, the
1540 // property might have been deleted (if it was introduced by eval)
1541 // before we reach the initialization point.
1542 //
1543 // Example:
1544 //
1545 // function f() { eval("delete x; const x;"); }
1546 //
1547 // In that case, the initialization behaves like a normal assignment
1548 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001551 // Property was found in a context. Perform the assignment if we
1552 // found some non-constant or an uninitialized constant.
1553 Handle<Context> context = Handle<Context>::cast(holder);
1554 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1555 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001556 }
1557 } else {
1558 // The holder is an arguments object.
1559 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001560 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001561 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001562 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001563 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 }
1565 return *value;
1566 }
1567
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001568 // The property could not be found, we introduce it in the global
1569 // context.
1570 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 Handle<JSObject> global = Handle<JSObject>(
1572 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001573 // Strict mode not needed (const disallowed in strict mode).
1574 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001575 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001576 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001577 return *value;
1578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001580 // The property was present in a context extension object.
1581 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001583 if (*context_ext == context->extension()) {
1584 // This is the property that was introduced by the const
1585 // declaration. Set it if it hasn't been set before. NOTE: We
1586 // cannot use GetProperty() to get the current value as it
1587 // 'unholes' the value.
1588 LookupResult lookup;
1589 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1590 ASSERT(lookup.IsProperty()); // the property was declared
1591 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1592
1593 PropertyType type = lookup.type();
1594 if (type == FIELD) {
1595 FixedArray* properties = context_ext->properties();
1596 int index = lookup.GetFieldIndex();
1597 if (properties->get(index)->IsTheHole()) {
1598 properties->set(index, *value);
1599 }
1600 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001601 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1602 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 }
1604 } else {
1605 // We should not reach here. Any real, named property should be
1606 // either a field or a dictionary slot.
1607 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 }
1609 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001610 // The property was found in a different context extension object.
1611 // Set it if it is not a read-only property.
1612 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001614 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 return *value;
1621}
1622
1623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001624RUNTIME_FUNCTION(MaybeObject*,
1625 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001626 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001627 ASSERT(args.length() == 2);
1628 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001629 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001630 if (object->HasFastProperties()) {
1631 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1632 }
1633 return *object;
1634}
1635
1636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001637RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001639 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001640 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1641 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001642 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001643 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001644 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001645 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001646 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001647 RUNTIME_ASSERT(index >= 0);
1648 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001650 Handle<Object> result = RegExpImpl::Exec(regexp,
1651 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001652 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001653 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001654 if (result.is_null()) return Failure::Exception();
1655 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656}
1657
1658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001659RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001661 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001663 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001664 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001665 Object* new_object;
1666 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1669 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001670 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1672 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001673 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1674 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001675 {
1676 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001678 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001680 }
1681 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001683 array->set_elements(elements);
1684 array->set_length(Smi::FromInt(elements_count));
1685 // Write in-object properties after the length of the array.
1686 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1687 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1688 return array;
1689}
1690
1691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001693 AssertNoAllocation no_alloc;
1694 ASSERT(args.length() == 5);
1695 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1696 CONVERT_CHECKED(String, source, args[1]);
1697
1698 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001700
1701 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001703
1704 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001706
1707 Map* map = regexp->map();
1708 Object* constructor = map->constructor();
1709 if (constructor->IsJSFunction() &&
1710 JSFunction::cast(constructor)->initial_map() == map) {
1711 // If we still have the original map, set in-object properties directly.
1712 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1713 // TODO(lrn): Consider skipping write barrier on booleans as well.
1714 // Both true and false should be in oldspace at all times.
1715 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1716 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1717 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1718 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1719 Smi::FromInt(0),
1720 SKIP_WRITE_BARRIER);
1721 return regexp;
1722 }
1723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001725 PropertyAttributes final =
1726 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1727 PropertyAttributes writable =
1728 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 source,
1733 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001736 global,
1737 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 ASSERT(!result->IsFailure());
1739 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001741 ignoreCase,
1742 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001745 multiline,
1746 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 ASSERT(!result->IsFailure());
1748 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001750 Smi::FromInt(0),
1751 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 ASSERT(!result->IsFailure());
1753 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001754 return regexp;
1755}
1756
1757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001758RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001760 ASSERT(args.length() == 1);
1761 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1762 // This is necessary to enable fast checks for absence of elements
1763 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001765 return Smi::FromInt(0);
1766}
1767
1768
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1770 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001772 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1774 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1775 Handle<JSFunction> optimized =
1776 isolate->factory()->NewFunction(key,
1777 JS_OBJECT_TYPE,
1778 JSObject::kHeaderSize,
1779 code,
1780 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001782 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783 return optimized;
1784}
1785
1786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001789 ASSERT(args.length() == 1);
1790 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1791
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001792 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1793 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1794 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1795 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1796 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1797 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1798 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001799
1800 return *holder;
1801}
1802
1803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001804RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001805 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 Context* global_context =
1807 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001808 return global_context->global()->global_receiver();
1809}
1810
1811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001812RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 ASSERT(args.length() == 4);
1815 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001816 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 Handle<String> pattern = args.at<String>(2);
1818 Handle<String> flags = args.at<String>(3);
1819
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001820 // Get the RegExp function from the context in the literals array.
1821 // This is the RegExp function from the context in which the
1822 // function was created. We do not use the RegExp function from the
1823 // current global context because this might be the RegExp function
1824 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001825 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001826 Handle<JSFunction>(
1827 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828 // Compute the regular expression literal.
1829 bool has_pending_exception;
1830 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001831 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1832 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 return Failure::Exception();
1836 }
1837 literals->set(index, *regexp);
1838 return *regexp;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843 NoHandleAllocation ha;
1844 ASSERT(args.length() == 1);
1845
1846 CONVERT_CHECKED(JSFunction, f, args[0]);
1847 return f->shared()->name();
1848}
1849
1850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001851RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001852 NoHandleAllocation ha;
1853 ASSERT(args.length() == 2);
1854
1855 CONVERT_CHECKED(JSFunction, f, args[0]);
1856 CONVERT_CHECKED(String, name, args[1]);
1857 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001859}
1860
1861
whesse@chromium.org7b260152011-06-20 15:33:18 +00001862RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1863 HandleScope scope(isolate);
1864 ASSERT(args.length() == 1);
1865
1866 CONVERT_CHECKED(JSFunction, fun, args[0]);
1867 fun->shared()->set_bound(true);
1868 return isolate->heap()->undefined_value();
1869}
1870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001872 NoHandleAllocation ha;
1873 ASSERT(args.length() == 1);
1874
1875 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001876 Object* obj = f->RemovePrototype();
1877 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001879 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001885 ASSERT(args.length() == 1);
1886
1887 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001888 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1889 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890
1891 return *GetScriptWrapper(Handle<Script>::cast(script));
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
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()->GetSourceCode();
1901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905 NoHandleAllocation ha;
1906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
1909 int pos = fun->shared()->start_position();
1910 return Smi::FromInt(pos);
1911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001915 ASSERT(args.length() == 2);
1916
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001917 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001918 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1919
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001920 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1921
1922 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001923 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 NoHandleAllocation ha;
1929 ASSERT(args.length() == 2);
1930
1931 CONVERT_CHECKED(JSFunction, fun, args[0]);
1932 CONVERT_CHECKED(String, name, args[1]);
1933 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 2);
1941
1942 CONVERT_CHECKED(JSFunction, fun, args[0]);
1943 CONVERT_CHECKED(Smi, length, args[1]);
1944 fun->shared()->set_length(length->value());
1945 return length;
1946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001950 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 ASSERT(args.length() == 2);
1952
1953 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001954 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001955 Object* obj;
1956 { MaybeObject* maybe_obj =
1957 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1958 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 return args[0]; // return TOS
1961}
1962
1963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001964RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001965 NoHandleAllocation ha;
1966 ASSERT(args.length() == 1);
1967
1968 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001969 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1970 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001971}
1972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001975 NoHandleAllocation ha;
1976 ASSERT(args.length() == 1);
1977
1978 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 return f->IsBuiltin() ? isolate->heap()->true_value() :
1980 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001981}
1982
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 2);
1987
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001988 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001989 Handle<Object> code = args.at<Object>(1);
1990
1991 Handle<Context> context(target->context());
1992
1993 if (!code->IsNull()) {
1994 RUNTIME_ASSERT(code->IsJSFunction());
1995 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997
1998 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 return Failure::Exception();
2000 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002001 // Since we don't store the source for this we should never
2002 // optimize this.
2003 shared->code()->set_optimizable(false);
2004
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002005 // Set the code, scope info, formal parameter count,
2006 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002007 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002009 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002011 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002013 // Set the source code of the target function to undefined.
2014 // SetCode is only used for built-in constructors like String,
2015 // Array, and Object, and some web code
2016 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002017 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002018 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002019 // Clear the optimization hints related to the compiled code as these are no
2020 // longer valid when the code is overwritten.
2021 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 context = Handle<Context>(fun->context());
2023
2024 // Make sure we get a fresh copy of the literal vector to avoid
2025 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002026 int number_of_literals = fun->NumberOfLiterals();
2027 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002030 // Insert the object, regexp and array functions in the literals
2031 // array prefix. These are the functions that will be used when
2032 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002033 literals->set(JSFunction::kLiteralGlobalContextIndex,
2034 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002036 // It's okay to skip the write barrier here because the literals
2037 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002038 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 }
2041
2042 target->set_context(*context);
2043 return *target;
2044}
2045
2046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002047RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002048 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002049 ASSERT(args.length() == 2);
2050 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002051 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002052 RUNTIME_ASSERT(num >= 0);
2053 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002055}
2056
2057
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002058MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2059 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002060 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002061 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002062 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002063 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002064 }
2065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002066 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002067}
2068
2069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002070RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071 NoHandleAllocation ha;
2072 ASSERT(args.length() == 2);
2073
2074 CONVERT_CHECKED(String, subject, args[0]);
2075 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002076 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002078 uint32_t i = 0;
2079 if (index->IsSmi()) {
2080 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002081 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002082 i = value;
2083 } else {
2084 ASSERT(index->IsHeapNumber());
2085 double value = HeapNumber::cast(index)->value();
2086 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002087 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002088
2089 // Flatten the string. If someone wants to get a char at an index
2090 // in a cons string, it is likely that more indices will be
2091 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002092 Object* flat;
2093 { MaybeObject* maybe_flat = subject->TryFlatten();
2094 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2095 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002096 subject = String::cast(flat);
2097
2098 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002099 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002100 }
2101
2102 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002103}
2104
2105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002106RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 NoHandleAllocation ha;
2108 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002109 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110}
2111
lrn@chromium.org25156de2010-04-06 13:10:27 +00002112
2113class FixedArrayBuilder {
2114 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002115 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2116 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002117 length_(0) {
2118 // Require a non-zero initial size. Ensures that doubling the size to
2119 // extend the array will work.
2120 ASSERT(initial_capacity > 0);
2121 }
2122
2123 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2124 : array_(backing_store),
2125 length_(0) {
2126 // Require a non-zero initial size. Ensures that doubling the size to
2127 // extend the array will work.
2128 ASSERT(backing_store->length() > 0);
2129 }
2130
2131 bool HasCapacity(int elements) {
2132 int length = array_->length();
2133 int required_length = length_ + elements;
2134 return (length >= required_length);
2135 }
2136
2137 void EnsureCapacity(int elements) {
2138 int length = array_->length();
2139 int required_length = length_ + elements;
2140 if (length < required_length) {
2141 int new_length = length;
2142 do {
2143 new_length *= 2;
2144 } while (new_length < required_length);
2145 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002147 array_->CopyTo(0, *extended_array, 0, length_);
2148 array_ = extended_array;
2149 }
2150 }
2151
2152 void Add(Object* value) {
2153 ASSERT(length_ < capacity());
2154 array_->set(length_, value);
2155 length_++;
2156 }
2157
2158 void Add(Smi* value) {
2159 ASSERT(length_ < capacity());
2160 array_->set(length_, value);
2161 length_++;
2162 }
2163
2164 Handle<FixedArray> array() {
2165 return array_;
2166 }
2167
2168 int length() {
2169 return length_;
2170 }
2171
2172 int capacity() {
2173 return array_->length();
2174 }
2175
2176 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002177 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002178 result_array->set_length(Smi::FromInt(length_));
2179 return result_array;
2180 }
2181
2182 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2183 target_array->set_elements(*array_);
2184 target_array->set_length(Smi::FromInt(length_));
2185 return target_array;
2186 }
2187
2188 private:
2189 Handle<FixedArray> array_;
2190 int length_;
2191};
2192
2193
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002195const int kStringBuilderConcatHelperLengthBits = 11;
2196const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002197
2198template <typename schar>
2199static inline void StringBuilderConcatHelper(String*,
2200 schar*,
2201 FixedArray*,
2202 int);
2203
lrn@chromium.org25156de2010-04-06 13:10:27 +00002204typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2205 StringBuilderSubstringLength;
2206typedef BitField<int,
2207 kStringBuilderConcatHelperLengthBits,
2208 kStringBuilderConcatHelperPositionBits>
2209 StringBuilderSubstringPosition;
2210
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211
2212class ReplacementStringBuilder {
2213 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 ReplacementStringBuilder(Heap* heap,
2215 Handle<String> subject,
2216 int estimated_part_count)
2217 : heap_(heap),
2218 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002219 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002221 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002222 // Require a non-zero initial size. Ensures that doubling the size to
2223 // extend the array will work.
2224 ASSERT(estimated_part_count > 0);
2225 }
2226
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2228 int from,
2229 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002230 ASSERT(from >= 0);
2231 int length = to - from;
2232 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002233 if (StringBuilderSubstringLength::is_valid(length) &&
2234 StringBuilderSubstringPosition::is_valid(from)) {
2235 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2236 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002237 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002238 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002239 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002240 builder->Add(Smi::FromInt(-length));
2241 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002242 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002243 }
2244
2245
2246 void EnsureCapacity(int elements) {
2247 array_builder_.EnsureCapacity(elements);
2248 }
2249
2250
2251 void AddSubjectSlice(int from, int to) {
2252 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002253 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002254 }
2255
2256
2257 void AddString(Handle<String> string) {
2258 int length = string->length();
2259 ASSERT(length > 0);
2260 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002261 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002262 is_ascii_ = false;
2263 }
2264 IncrementCharacterCount(length);
2265 }
2266
2267
2268 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002271 }
2272
2273 Handle<String> joined_string;
2274 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002275 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002277 char* char_buffer = seq->GetChars();
2278 StringBuilderConcatHelper(*subject_,
2279 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 *array_builder_.array(),
2281 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002282 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 } else {
2284 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002285 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 uc16* char_buffer = seq->GetChars();
2288 StringBuilderConcatHelper(*subject_,
2289 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 *array_builder_.array(),
2291 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002292 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 }
2294 return joined_string;
2295 }
2296
2297
2298 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002299 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 V8::FatalProcessOutOfMemory("String.replace result too large.");
2301 }
2302 character_count_ += by;
2303 }
2304
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002306 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002307 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002308
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002310 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2311 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 }
2313
2314
ager@chromium.org04921a82011-06-27 13:21:41 +00002315 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2316 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 }
2318
2319
2320 void AddElement(Object* element) {
2321 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 ASSERT(array_builder_.capacity() > array_builder_.length());
2323 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002324 }
2325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002326 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002328 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002329 int character_count_;
2330 bool is_ascii_;
2331};
2332
2333
2334class CompiledReplacement {
2335 public:
2336 CompiledReplacement()
2337 : parts_(1), replacement_substrings_(0) {}
2338
2339 void Compile(Handle<String> replacement,
2340 int capture_count,
2341 int subject_length);
2342
2343 void Apply(ReplacementStringBuilder* builder,
2344 int match_from,
2345 int match_to,
2346 Handle<JSArray> last_match_info);
2347
2348 // Number of distinct parts of the replacement pattern.
2349 int parts() {
2350 return parts_.length();
2351 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353 private:
2354 enum PartType {
2355 SUBJECT_PREFIX = 1,
2356 SUBJECT_SUFFIX,
2357 SUBJECT_CAPTURE,
2358 REPLACEMENT_SUBSTRING,
2359 REPLACEMENT_STRING,
2360
2361 NUMBER_OF_PART_TYPES
2362 };
2363
2364 struct ReplacementPart {
2365 static inline ReplacementPart SubjectMatch() {
2366 return ReplacementPart(SUBJECT_CAPTURE, 0);
2367 }
2368 static inline ReplacementPart SubjectCapture(int capture_index) {
2369 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2370 }
2371 static inline ReplacementPart SubjectPrefix() {
2372 return ReplacementPart(SUBJECT_PREFIX, 0);
2373 }
2374 static inline ReplacementPart SubjectSuffix(int subject_length) {
2375 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2376 }
2377 static inline ReplacementPart ReplacementString() {
2378 return ReplacementPart(REPLACEMENT_STRING, 0);
2379 }
2380 static inline ReplacementPart ReplacementSubString(int from, int to) {
2381 ASSERT(from >= 0);
2382 ASSERT(to > from);
2383 return ReplacementPart(-from, to);
2384 }
2385
2386 // If tag <= 0 then it is the negation of a start index of a substring of
2387 // the replacement pattern, otherwise it's a value from PartType.
2388 ReplacementPart(int tag, int data)
2389 : tag(tag), data(data) {
2390 // Must be non-positive or a PartType value.
2391 ASSERT(tag < NUMBER_OF_PART_TYPES);
2392 }
2393 // Either a value of PartType or a non-positive number that is
2394 // the negation of an index into the replacement string.
2395 int tag;
2396 // The data value's interpretation depends on the value of tag:
2397 // tag == SUBJECT_PREFIX ||
2398 // tag == SUBJECT_SUFFIX: data is unused.
2399 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2400 // tag == REPLACEMENT_SUBSTRING ||
2401 // tag == REPLACEMENT_STRING: data is index into array of substrings
2402 // of the replacement string.
2403 // tag <= 0: Temporary representation of the substring of the replacement
2404 // string ranging over -tag .. data.
2405 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2406 // substring objects.
2407 int data;
2408 };
2409
2410 template<typename Char>
2411 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2412 Vector<Char> characters,
2413 int capture_count,
2414 int subject_length) {
2415 int length = characters.length();
2416 int last = 0;
2417 for (int i = 0; i < length; i++) {
2418 Char c = characters[i];
2419 if (c == '$') {
2420 int next_index = i + 1;
2421 if (next_index == length) { // No next character!
2422 break;
2423 }
2424 Char c2 = characters[next_index];
2425 switch (c2) {
2426 case '$':
2427 if (i > last) {
2428 // There is a substring before. Include the first "$".
2429 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2430 last = next_index + 1; // Continue after the second "$".
2431 } else {
2432 // Let the next substring start with the second "$".
2433 last = next_index;
2434 }
2435 i = next_index;
2436 break;
2437 case '`':
2438 if (i > last) {
2439 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2440 }
2441 parts->Add(ReplacementPart::SubjectPrefix());
2442 i = next_index;
2443 last = i + 1;
2444 break;
2445 case '\'':
2446 if (i > last) {
2447 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2448 }
2449 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2450 i = next_index;
2451 last = i + 1;
2452 break;
2453 case '&':
2454 if (i > last) {
2455 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2456 }
2457 parts->Add(ReplacementPart::SubjectMatch());
2458 i = next_index;
2459 last = i + 1;
2460 break;
2461 case '0':
2462 case '1':
2463 case '2':
2464 case '3':
2465 case '4':
2466 case '5':
2467 case '6':
2468 case '7':
2469 case '8':
2470 case '9': {
2471 int capture_ref = c2 - '0';
2472 if (capture_ref > capture_count) {
2473 i = next_index;
2474 continue;
2475 }
2476 int second_digit_index = next_index + 1;
2477 if (second_digit_index < length) {
2478 // Peek ahead to see if we have two digits.
2479 Char c3 = characters[second_digit_index];
2480 if ('0' <= c3 && c3 <= '9') { // Double digits.
2481 int double_digit_ref = capture_ref * 10 + c3 - '0';
2482 if (double_digit_ref <= capture_count) {
2483 next_index = second_digit_index;
2484 capture_ref = double_digit_ref;
2485 }
2486 }
2487 }
2488 if (capture_ref > 0) {
2489 if (i > last) {
2490 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2491 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002492 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2494 last = next_index + 1;
2495 }
2496 i = next_index;
2497 break;
2498 }
2499 default:
2500 i = next_index;
2501 break;
2502 }
2503 }
2504 }
2505 if (length > last) {
2506 if (last == 0) {
2507 parts->Add(ReplacementPart::ReplacementString());
2508 } else {
2509 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2510 }
2511 }
2512 }
2513
2514 ZoneList<ReplacementPart> parts_;
2515 ZoneList<Handle<String> > replacement_substrings_;
2516};
2517
2518
2519void CompiledReplacement::Compile(Handle<String> replacement,
2520 int capture_count,
2521 int subject_length) {
2522 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002523 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524 AssertNoAllocation no_alloc;
2525 ParseReplacementPattern(&parts_,
2526 replacement->ToAsciiVector(),
2527 capture_count,
2528 subject_length);
2529 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002530 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002531 AssertNoAllocation no_alloc;
2532
2533 ParseReplacementPattern(&parts_,
2534 replacement->ToUC16Vector(),
2535 capture_count,
2536 subject_length);
2537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002538 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002539 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002540 int substring_index = 0;
2541 for (int i = 0, n = parts_.length(); i < n; i++) {
2542 int tag = parts_[i].tag;
2543 if (tag <= 0) { // A replacement string slice.
2544 int from = -tag;
2545 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002546 replacement_substrings_.Add(
2547 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002548 parts_[i].tag = REPLACEMENT_SUBSTRING;
2549 parts_[i].data = substring_index;
2550 substring_index++;
2551 } else if (tag == REPLACEMENT_STRING) {
2552 replacement_substrings_.Add(replacement);
2553 parts_[i].data = substring_index;
2554 substring_index++;
2555 }
2556 }
2557}
2558
2559
2560void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2561 int match_from,
2562 int match_to,
2563 Handle<JSArray> last_match_info) {
2564 for (int i = 0, n = parts_.length(); i < n; i++) {
2565 ReplacementPart part = parts_[i];
2566 switch (part.tag) {
2567 case SUBJECT_PREFIX:
2568 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2569 break;
2570 case SUBJECT_SUFFIX: {
2571 int subject_length = part.data;
2572 if (match_to < subject_length) {
2573 builder->AddSubjectSlice(match_to, subject_length);
2574 }
2575 break;
2576 }
2577 case SUBJECT_CAPTURE: {
2578 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002579 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2581 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2582 if (from >= 0 && to > from) {
2583 builder->AddSubjectSlice(from, to);
2584 }
2585 break;
2586 }
2587 case REPLACEMENT_SUBSTRING:
2588 case REPLACEMENT_STRING:
2589 builder->AddString(replacement_substrings_[part.data]);
2590 break;
2591 default:
2592 UNREACHABLE();
2593 }
2594 }
2595}
2596
2597
2598
lrn@chromium.org303ada72010-10-27 09:33:13 +00002599MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002600 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002601 String* subject,
2602 JSRegExp* regexp,
2603 String* replacement,
2604 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 ASSERT(subject->IsFlat());
2606 ASSERT(replacement->IsFlat());
2607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002608 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002609
2610 int length = subject->length();
2611 Handle<String> subject_handle(subject);
2612 Handle<JSRegExp> regexp_handle(regexp);
2613 Handle<String> replacement_handle(replacement);
2614 Handle<JSArray> last_match_info_handle(last_match_info);
2615 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2616 subject_handle,
2617 0,
2618 last_match_info_handle);
2619 if (match.is_null()) {
2620 return Failure::Exception();
2621 }
2622 if (match->IsNull()) {
2623 return *subject_handle;
2624 }
2625
2626 int capture_count = regexp_handle->CaptureCount();
2627
2628 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002629 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002630 CompiledReplacement compiled_replacement;
2631 compiled_replacement.Compile(replacement_handle,
2632 capture_count,
2633 length);
2634
2635 bool is_global = regexp_handle->GetFlags().is_global();
2636
2637 // Guessing the number of parts that the final result string is built
2638 // from. Global regexps can match any number of times, so we guess
2639 // conservatively.
2640 int expected_parts =
2641 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002642 ReplacementStringBuilder builder(isolate->heap(),
2643 subject_handle,
2644 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002645
2646 // Index of end of last match.
2647 int prev = 0;
2648
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002649 // Number of parts added by compiled replacement plus preceeding
2650 // string and possibly suffix after last match. It is possible for
2651 // all components to use two elements when encoded as two smis.
2652 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653 bool matched = true;
2654 do {
2655 ASSERT(last_match_info_handle->HasFastElements());
2656 // Increase the capacity of the builder before entering local handle-scope,
2657 // so its internal buffer can safely allocate a new handle if it grows.
2658 builder.EnsureCapacity(parts_added_per_loop);
2659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002660 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002661 int start, end;
2662 {
2663 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002664 FixedArray* match_info_array =
2665 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666
2667 ASSERT_EQ(capture_count * 2 + 2,
2668 RegExpImpl::GetLastCaptureCount(match_info_array));
2669 start = RegExpImpl::GetCapture(match_info_array, 0);
2670 end = RegExpImpl::GetCapture(match_info_array, 1);
2671 }
2672
2673 if (prev < start) {
2674 builder.AddSubjectSlice(prev, start);
2675 }
2676 compiled_replacement.Apply(&builder,
2677 start,
2678 end,
2679 last_match_info_handle);
2680 prev = end;
2681
2682 // Only continue checking for global regexps.
2683 if (!is_global) break;
2684
2685 // Continue from where the match ended, unless it was an empty match.
2686 int next = end;
2687 if (start == end) {
2688 next = end + 1;
2689 if (next > length) break;
2690 }
2691
2692 match = RegExpImpl::Exec(regexp_handle,
2693 subject_handle,
2694 next,
2695 last_match_info_handle);
2696 if (match.is_null()) {
2697 return Failure::Exception();
2698 }
2699 matched = !match->IsNull();
2700 } while (matched);
2701
2702 if (prev < length) {
2703 builder.AddSubjectSlice(prev, length);
2704 }
2705
2706 return *(builder.ToString());
2707}
2708
2709
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002710template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002711MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002713 String* subject,
2714 JSRegExp* regexp,
2715 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002716 ASSERT(subject->IsFlat());
2717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002718 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002719
2720 Handle<String> subject_handle(subject);
2721 Handle<JSRegExp> regexp_handle(regexp);
2722 Handle<JSArray> last_match_info_handle(last_match_info);
2723 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2724 subject_handle,
2725 0,
2726 last_match_info_handle);
2727 if (match.is_null()) return Failure::Exception();
2728 if (match->IsNull()) return *subject_handle;
2729
2730 ASSERT(last_match_info_handle->HasFastElements());
2731
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002732 int start, end;
2733 {
2734 AssertNoAllocation match_info_array_is_not_in_a_handle;
2735 FixedArray* match_info_array =
2736 FixedArray::cast(last_match_info_handle->elements());
2737
2738 start = RegExpImpl::GetCapture(match_info_array, 0);
2739 end = RegExpImpl::GetCapture(match_info_array, 1);
2740 }
2741
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002742 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002743 int new_length = length - (end - start);
2744 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002745 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002746 }
2747 Handle<ResultSeqString> answer;
2748 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002749 answer = Handle<ResultSeqString>::cast(
2750 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002751 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 answer = Handle<ResultSeqString>::cast(
2753 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002754 }
2755
2756 // If the regexp isn't global, only match once.
2757 if (!regexp_handle->GetFlags().is_global()) {
2758 if (start > 0) {
2759 String::WriteToFlat(*subject_handle,
2760 answer->GetChars(),
2761 0,
2762 start);
2763 }
2764 if (end < length) {
2765 String::WriteToFlat(*subject_handle,
2766 answer->GetChars() + start,
2767 end,
2768 length);
2769 }
2770 return *answer;
2771 }
2772
2773 int prev = 0; // Index of end of last match.
2774 int next = 0; // Start of next search (prev unless last match was empty).
2775 int position = 0;
2776
2777 do {
2778 if (prev < start) {
2779 // Add substring subject[prev;start] to answer string.
2780 String::WriteToFlat(*subject_handle,
2781 answer->GetChars() + position,
2782 prev,
2783 start);
2784 position += start - prev;
2785 }
2786 prev = end;
2787 next = end;
2788 // Continue from where the match ended, unless it was an empty match.
2789 if (start == end) {
2790 next++;
2791 if (next > length) break;
2792 }
2793 match = RegExpImpl::Exec(regexp_handle,
2794 subject_handle,
2795 next,
2796 last_match_info_handle);
2797 if (match.is_null()) return Failure::Exception();
2798 if (match->IsNull()) break;
2799
2800 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002801 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002802 {
2803 AssertNoAllocation match_info_array_is_not_in_a_handle;
2804 FixedArray* match_info_array =
2805 FixedArray::cast(last_match_info_handle->elements());
2806 start = RegExpImpl::GetCapture(match_info_array, 0);
2807 end = RegExpImpl::GetCapture(match_info_array, 1);
2808 }
2809 } while (true);
2810
2811 if (prev < length) {
2812 // Add substring subject[prev;length] to answer string.
2813 String::WriteToFlat(*subject_handle,
2814 answer->GetChars() + position,
2815 prev,
2816 length);
2817 position += length - prev;
2818 }
2819
2820 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822 }
2823
2824 // Shorten string and fill
2825 int string_size = ResultSeqString::SizeFor(position);
2826 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2827 int delta = allocated_string_size - string_size;
2828
2829 answer->set_length(position);
2830 if (delta == 0) return *answer;
2831
2832 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002833 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002834
2835 return *answer;
2836}
2837
2838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002839RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002840 ASSERT(args.length() == 4);
2841
2842 CONVERT_CHECKED(String, subject, args[0]);
2843 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002844 Object* flat_subject;
2845 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2846 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2847 return maybe_flat_subject;
2848 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002849 }
2850 subject = String::cast(flat_subject);
2851 }
2852
2853 CONVERT_CHECKED(String, replacement, args[2]);
2854 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002855 Object* flat_replacement;
2856 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2857 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2858 return maybe_flat_replacement;
2859 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002860 }
2861 replacement = String::cast(flat_replacement);
2862 }
2863
2864 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2865 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2866
2867 ASSERT(last_match_info->HasFastElements());
2868
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002869 if (replacement->length() == 0) {
2870 if (subject->HasOnlyAsciiChars()) {
2871 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002872 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002873 } else {
2874 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002875 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876 }
2877 }
2878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 return StringReplaceRegExpWithString(isolate,
2880 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002881 regexp,
2882 replacement,
2883 last_match_info);
2884}
2885
2886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887// Perform string match of pattern on subject, starting at start index.
2888// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002889// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002890int Runtime::StringMatch(Isolate* isolate,
2891 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002892 Handle<String> pat,
2893 int start_index) {
2894 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002895 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002896
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002897 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002898 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002900 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002901 if (start_index + pattern_length > subject_length) return -1;
2902
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002903 if (!sub->IsFlat()) FlattenString(sub);
2904 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002905
ager@chromium.org7c537e22008-10-16 08:43:32 +00002906 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002907 // Extract flattened substrings of cons strings before determining asciiness.
2908 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002909 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002910 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002911 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002912
ager@chromium.org7c537e22008-10-16 08:43:32 +00002913 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 if (seq_pat->IsAsciiRepresentation()) {
2915 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2916 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 return SearchString(isolate,
2918 seq_sub->ToAsciiVector(),
2919 pat_vector,
2920 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 return SearchString(isolate,
2923 seq_sub->ToUC16Vector(),
2924 pat_vector,
2925 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002926 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002927 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2928 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 return SearchString(isolate,
2930 seq_sub->ToAsciiVector(),
2931 pat_vector,
2932 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002934 return SearchString(isolate,
2935 seq_sub->ToUC16Vector(),
2936 pat_vector,
2937 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002938}
2939
2940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002941RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002942 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002943 ASSERT(args.length() == 3);
2944
ager@chromium.org7c537e22008-10-16 08:43:32 +00002945 CONVERT_ARG_CHECKED(String, sub, 0);
2946 CONVERT_ARG_CHECKED(String, pat, 1);
2947
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002948 Object* index = args[2];
2949 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002950 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002951
ager@chromium.org870a0b62008-11-04 11:43:05 +00002952 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002953 int position =
2954 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002955 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002956}
2957
2958
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002959template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960static int StringMatchBackwards(Vector<const schar> subject,
2961 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002962 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002963 int pattern_length = pattern.length();
2964 ASSERT(pattern_length >= 1);
2965 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966
2967 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002968 for (int i = 0; i < pattern_length; i++) {
2969 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970 if (c > String::kMaxAsciiCharCode) {
2971 return -1;
2972 }
2973 }
2974 }
2975
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002976 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002977 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002978 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002980 while (j < pattern_length) {
2981 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982 break;
2983 }
2984 j++;
2985 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002986 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002987 return i;
2988 }
2989 }
2990 return -1;
2991}
2992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002993RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002995 ASSERT(args.length() == 3);
2996
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002997 CONVERT_ARG_CHECKED(String, sub, 0);
2998 CONVERT_ARG_CHECKED(String, pat, 1);
2999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003002 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003004 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003005 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003007 if (start_index + pat_length > sub_length) {
3008 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 if (pat_length == 0) {
3012 return Smi::FromInt(start_index);
3013 }
3014
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003015 if (!sub->IsFlat()) FlattenString(sub);
3016 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003017
3018 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3019
3020 int position = -1;
3021
3022 if (pat->IsAsciiRepresentation()) {
3023 Vector<const char> pat_vector = pat->ToAsciiVector();
3024 if (sub->IsAsciiRepresentation()) {
3025 position = StringMatchBackwards(sub->ToAsciiVector(),
3026 pat_vector,
3027 start_index);
3028 } else {
3029 position = StringMatchBackwards(sub->ToUC16Vector(),
3030 pat_vector,
3031 start_index);
3032 }
3033 } else {
3034 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3035 if (sub->IsAsciiRepresentation()) {
3036 position = StringMatchBackwards(sub->ToAsciiVector(),
3037 pat_vector,
3038 start_index);
3039 } else {
3040 position = StringMatchBackwards(sub->ToUC16Vector(),
3041 pat_vector,
3042 start_index);
3043 }
3044 }
3045
3046 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003047}
3048
3049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003050RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003051 NoHandleAllocation ha;
3052 ASSERT(args.length() == 2);
3053
3054 CONVERT_CHECKED(String, str1, args[0]);
3055 CONVERT_CHECKED(String, str2, args[1]);
3056
3057 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058 int str1_length = str1->length();
3059 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003060
3061 // Decide trivial cases without flattening.
3062 if (str1_length == 0) {
3063 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3064 return Smi::FromInt(-str2_length);
3065 } else {
3066 if (str2_length == 0) return Smi::FromInt(str1_length);
3067 }
3068
3069 int end = str1_length < str2_length ? str1_length : str2_length;
3070
3071 // No need to flatten if we are going to find the answer on the first
3072 // character. At this point we know there is at least one character
3073 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075 if (d != 0) return Smi::FromInt(d);
3076
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003077 str1->TryFlatten();
3078 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003080 StringInputBuffer& buf1 =
3081 *isolate->runtime_state()->string_locale_compare_buf1();
3082 StringInputBuffer& buf2 =
3083 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003084
3085 buf1.Reset(str1);
3086 buf2.Reset(str2);
3087
3088 for (int i = 0; i < end; i++) {
3089 uint16_t char1 = buf1.GetNext();
3090 uint16_t char2 = buf2.GetNext();
3091 if (char1 != char2) return Smi::FromInt(char1 - char2);
3092 }
3093
3094 return Smi::FromInt(str1_length - str2_length);
3095}
3096
3097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003098RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099 NoHandleAllocation ha;
3100 ASSERT(args.length() == 3);
3101
3102 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003103 int start, end;
3104 // We have a fast integer-only case here to avoid a conversion to double in
3105 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003106 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3107 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3108 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3109 start = from_number;
3110 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003111 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003112 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3113 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003114 start = FastD2I(from_number);
3115 end = FastD2I(to_number);
3116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117 RUNTIME_ASSERT(end >= start);
3118 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003119 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003121 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122}
3123
3124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003125RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 ASSERT_EQ(3, args.length());
3127
3128 CONVERT_ARG_CHECKED(String, subject, 0);
3129 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3130 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3131 HandleScope handles;
3132
3133 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3134
3135 if (match.is_null()) {
3136 return Failure::Exception();
3137 }
3138 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 }
3141 int length = subject->length();
3142
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003143 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003145 int start;
3146 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003148 {
3149 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003150 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003151 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3152 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3153 }
3154 offsets.Add(start);
3155 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003156 if (start == end) if (++end > length) break;
3157 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 if (match.is_null()) {
3159 return Failure::Exception();
3160 }
3161 } while (!match->IsNull());
3162 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003163 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003164 Handle<String> substring = isolate->factory()->
3165 NewSubString(subject, offsets.at(0), offsets.at(1));
3166 elements->set(0, *substring);
3167 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003168 int from = offsets.at(i * 2);
3169 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003170 Handle<String> substring = isolate->factory()->
3171 NewProperSubString(subject, from, to);
3172 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003173 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003174 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003175 result->set_length(Smi::FromInt(matches));
3176 return *result;
3177}
3178
3179
lrn@chromium.org25156de2010-04-06 13:10:27 +00003180// Two smis before and after the match, for very long strings.
3181const int kMaxBuilderEntriesPerRegExpMatch = 5;
3182
3183
3184static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3185 Handle<JSArray> last_match_info,
3186 int match_start,
3187 int match_end) {
3188 // Fill last_match_info with a single capture.
3189 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3190 AssertNoAllocation no_gc;
3191 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3192 RegExpImpl::SetLastCaptureCount(elements, 2);
3193 RegExpImpl::SetLastInput(elements, *subject);
3194 RegExpImpl::SetLastSubject(elements, *subject);
3195 RegExpImpl::SetCapture(elements, 0, match_start);
3196 RegExpImpl::SetCapture(elements, 1, match_end);
3197}
3198
3199
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003200template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003201static bool SearchStringMultiple(Isolate* isolate,
3202 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003203 Vector<const PatternChar> pattern,
3204 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 FixedArrayBuilder* builder,
3206 int* match_pos) {
3207 int pos = *match_pos;
3208 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003209 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003210 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003211 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212 while (pos <= max_search_start) {
3213 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3214 *match_pos = pos;
3215 return false;
3216 }
3217 // Position of end of previous match.
3218 int match_end = pos + pattern_length;
3219 int new_pos = search.Search(subject, match_end);
3220 if (new_pos >= 0) {
3221 // A match.
3222 if (new_pos > match_end) {
3223 ReplacementStringBuilder::AddSubjectSlice(builder,
3224 match_end,
3225 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003226 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003227 pos = new_pos;
3228 builder->Add(pattern_string);
3229 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003230 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003231 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003232 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003233
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 if (pos < max_search_start) {
3235 ReplacementStringBuilder::AddSubjectSlice(builder,
3236 pos + pattern_length,
3237 subject_length);
3238 }
3239 *match_pos = pos;
3240 return true;
3241}
3242
3243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244static bool SearchStringMultiple(Isolate* isolate,
3245 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003246 Handle<String> pattern,
3247 Handle<JSArray> last_match_info,
3248 FixedArrayBuilder* builder) {
3249 ASSERT(subject->IsFlat());
3250 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251
3252 // Treating as if a previous match was before first character.
3253 int match_pos = -pattern->length();
3254
3255 for (;;) { // Break when search complete.
3256 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3257 AssertNoAllocation no_gc;
3258 if (subject->IsAsciiRepresentation()) {
3259 Vector<const char> subject_vector = subject->ToAsciiVector();
3260 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 if (SearchStringMultiple(isolate,
3262 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003263 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003264 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 builder,
3266 &match_pos)) break;
3267 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 if (SearchStringMultiple(isolate,
3269 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003270 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003271 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 builder,
3273 &match_pos)) break;
3274 }
3275 } else {
3276 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3277 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 if (SearchStringMultiple(isolate,
3279 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003280 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003281 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003282 builder,
3283 &match_pos)) break;
3284 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003285 if (SearchStringMultiple(isolate,
3286 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003287 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003288 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003289 builder,
3290 &match_pos)) break;
3291 }
3292 }
3293 }
3294
3295 if (match_pos >= 0) {
3296 SetLastMatchInfoNoCaptures(subject,
3297 last_match_info,
3298 match_pos,
3299 match_pos + pattern->length());
3300 return true;
3301 }
3302 return false; // No matches at all.
3303}
3304
3305
3306static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 Handle<String> subject,
3309 Handle<JSRegExp> regexp,
3310 Handle<JSArray> last_match_array,
3311 FixedArrayBuilder* builder) {
3312 ASSERT(subject->IsFlat());
3313 int match_start = -1;
3314 int match_end = 0;
3315 int pos = 0;
3316 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3317 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3318
3319 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003320 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003321 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003322 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003323
3324 for (;;) { // Break on failure, return on exception.
3325 RegExpImpl::IrregexpResult result =
3326 RegExpImpl::IrregexpExecOnce(regexp,
3327 subject,
3328 pos,
3329 register_vector);
3330 if (result == RegExpImpl::RE_SUCCESS) {
3331 match_start = register_vector[0];
3332 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3333 if (match_end < match_start) {
3334 ReplacementStringBuilder::AddSubjectSlice(builder,
3335 match_end,
3336 match_start);
3337 }
3338 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003339 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003340 if (!first) {
3341 builder->Add(*isolate->factory()->NewProperSubString(subject,
3342 match_start,
3343 match_end));
3344 } else {
3345 builder->Add(*isolate->factory()->NewSubString(subject,
3346 match_start,
3347 match_end));
3348 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003349 if (match_start != match_end) {
3350 pos = match_end;
3351 } else {
3352 pos = match_end + 1;
3353 if (pos > subject_length) break;
3354 }
3355 } else if (result == RegExpImpl::RE_FAILURE) {
3356 break;
3357 } else {
3358 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3359 return result;
3360 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003361 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003362 }
3363
3364 if (match_start >= 0) {
3365 if (match_end < subject_length) {
3366 ReplacementStringBuilder::AddSubjectSlice(builder,
3367 match_end,
3368 subject_length);
3369 }
3370 SetLastMatchInfoNoCaptures(subject,
3371 last_match_array,
3372 match_start,
3373 match_end);
3374 return RegExpImpl::RE_SUCCESS;
3375 } else {
3376 return RegExpImpl::RE_FAILURE; // No matches at all.
3377 }
3378}
3379
3380
3381static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003383 Handle<String> subject,
3384 Handle<JSRegExp> regexp,
3385 Handle<JSArray> last_match_array,
3386 FixedArrayBuilder* builder) {
3387
3388 ASSERT(subject->IsFlat());
3389 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3390 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3391
3392 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003393 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003394
3395 RegExpImpl::IrregexpResult result =
3396 RegExpImpl::IrregexpExecOnce(regexp,
3397 subject,
3398 0,
3399 register_vector);
3400
3401 int capture_count = regexp->CaptureCount();
3402 int subject_length = subject->length();
3403
3404 // Position to search from.
3405 int pos = 0;
3406 // End of previous match. Differs from pos if match was empty.
3407 int match_end = 0;
3408 if (result == RegExpImpl::RE_SUCCESS) {
3409 // Need to keep a copy of the previous match for creating last_match_info
3410 // at the end, so we have two vectors that we swap between.
3411 OffsetsVector registers2(required_registers);
3412 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003413 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003414 do {
3415 int match_start = register_vector[0];
3416 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3417 if (match_end < match_start) {
3418 ReplacementStringBuilder::AddSubjectSlice(builder,
3419 match_end,
3420 match_start);
3421 }
3422 match_end = register_vector[1];
3423
3424 {
3425 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003426 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003427 // Arguments array to replace function is match, captures, index and
3428 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 Handle<FixedArray> elements =
3430 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003431 Handle<String> match;
3432 if (!first) {
3433 match = isolate->factory()->NewProperSubString(subject,
3434 match_start,
3435 match_end);
3436 } else {
3437 match = isolate->factory()->NewSubString(subject,
3438 match_start,
3439 match_end);
3440 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003441 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003442 for (int i = 1; i <= capture_count; i++) {
3443 int start = register_vector[i * 2];
3444 if (start >= 0) {
3445 int end = register_vector[i * 2 + 1];
3446 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003447 Handle<String> substring;
3448 if (!first) {
3449 substring = isolate->factory()->NewProperSubString(subject,
3450 start,
3451 end);
3452 } else {
3453 substring = isolate->factory()->NewSubString(subject, start, end);
3454 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003455 elements->set(i, *substring);
3456 } else {
3457 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003459 }
3460 }
3461 elements->set(capture_count + 1, Smi::FromInt(match_start));
3462 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003463 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003464 }
3465 // Swap register vectors, so the last successful match is in
3466 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003467 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468 prev_register_vector = register_vector;
3469 register_vector = tmp;
3470
3471 if (match_end > match_start) {
3472 pos = match_end;
3473 } else {
3474 pos = match_end + 1;
3475 if (pos > subject_length) {
3476 break;
3477 }
3478 }
3479
3480 result = RegExpImpl::IrregexpExecOnce(regexp,
3481 subject,
3482 pos,
3483 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003484 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003485 } while (result == RegExpImpl::RE_SUCCESS);
3486
3487 if (result != RegExpImpl::RE_EXCEPTION) {
3488 // Finished matching, with at least one match.
3489 if (match_end < subject_length) {
3490 ReplacementStringBuilder::AddSubjectSlice(builder,
3491 match_end,
3492 subject_length);
3493 }
3494
3495 int last_match_capture_count = (capture_count + 1) * 2;
3496 int last_match_array_size =
3497 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3498 last_match_array->EnsureSize(last_match_array_size);
3499 AssertNoAllocation no_gc;
3500 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3501 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3502 RegExpImpl::SetLastSubject(elements, *subject);
3503 RegExpImpl::SetLastInput(elements, *subject);
3504 for (int i = 0; i < last_match_capture_count; i++) {
3505 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3506 }
3507 return RegExpImpl::RE_SUCCESS;
3508 }
3509 }
3510 // No matches at all, return failure or exception result directly.
3511 return result;
3512}
3513
3514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003515RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003517 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518
3519 CONVERT_ARG_CHECKED(String, subject, 1);
3520 if (!subject->IsFlat()) { FlattenString(subject); }
3521 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3522 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3523 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3524
3525 ASSERT(last_match_info->HasFastElements());
3526 ASSERT(regexp->GetFlags().is_global());
3527 Handle<FixedArray> result_elements;
3528 if (result_array->HasFastElements()) {
3529 result_elements =
3530 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003531 }
3532 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003534 }
3535 FixedArrayBuilder builder(result_elements);
3536
3537 if (regexp->TypeTag() == JSRegExp::ATOM) {
3538 Handle<String> pattern(
3539 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003540 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003541 if (SearchStringMultiple(isolate, subject, pattern,
3542 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003543 return *builder.ToJSArray(result_array);
3544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003546 }
3547
3548 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3549
3550 RegExpImpl::IrregexpResult result;
3551 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 result = SearchRegExpNoCaptureMultiple(isolate,
3553 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003554 regexp,
3555 last_match_info,
3556 &builder);
3557 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 result = SearchRegExpMultiple(isolate,
3559 subject,
3560 regexp,
3561 last_match_info,
3562 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003563 }
3564 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003566 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3567 return Failure::Exception();
3568}
3569
3570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 NoHandleAllocation ha;
3573 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003575 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003576
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003577 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003578 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003579 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003580 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003581 // Character array used for conversion.
3582 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 return isolate->heap()->
3584 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003585 }
3586 }
3587
3588 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003589 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593 if (isinf(value)) {
3594 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003600 MaybeObject* result =
3601 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 DeleteArray(str);
3603 return result;
3604}
3605
3606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003607RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 NoHandleAllocation ha;
3609 ASSERT(args.length() == 2);
3610
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003611 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 }
3615 if (isinf(value)) {
3616 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003621 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 int f = FastD2I(f_number);
3623 RUNTIME_ASSERT(f >= 0);
3624 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 MaybeObject* res =
3626 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629}
3630
3631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003632RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 NoHandleAllocation ha;
3634 ASSERT(args.length() == 2);
3635
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003636 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003638 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003639 }
3640 if (isinf(value)) {
3641 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003646 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 int f = FastD2I(f_number);
3648 RUNTIME_ASSERT(f >= -1 && f <= 20);
3649 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003650 MaybeObject* res =
3651 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654}
3655
3656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003657RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 NoHandleAllocation ha;
3659 ASSERT(args.length() == 2);
3660
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003661 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 }
3665 if (isinf(value)) {
3666 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003671 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 int f = FastD2I(f_number);
3673 RUNTIME_ASSERT(f >= 1 && f <= 21);
3674 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003675 MaybeObject* res =
3676 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003677 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679}
3680
3681
3682// Returns a single character string where first character equals
3683// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003685 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003686 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003687 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003688 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003690 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691}
3692
3693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3695 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003696 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003697 // Handle [] indexing on Strings
3698 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3700 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 }
3702
3703 // Handle [] indexing on String objects
3704 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3706 Handle<Object> result =
3707 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3708 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 }
3710
3711 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 return prototype->GetElement(index);
3714 }
3715
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003716 return GetElement(object, index);
3717}
3718
3719
lrn@chromium.org303ada72010-10-27 09:33:13 +00003720MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 return object->GetElement(index);
3722}
3723
3724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3726 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003727 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003730 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 isolate->factory()->NewTypeError("non_object_property_load",
3734 HandleVector(args, 2));
3735 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 }
3737
3738 // Check if the given key is an array index.
3739 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003740 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 }
3743
3744 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003745 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003747 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 bool has_pending_exception = false;
3750 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003751 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003753 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754 }
3755
ager@chromium.org32912102009-01-16 10:38:43 +00003756 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 // the element if so.
3758 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003761 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 }
3763}
3764
3765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003766RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 NoHandleAllocation ha;
3768 ASSERT(args.length() == 2);
3769
3770 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003771 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003777// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003778RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003779 NoHandleAllocation ha;
3780 ASSERT(args.length() == 2);
3781
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003782 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003783 // itself.
3784 //
3785 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003786 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003787 // global proxy object never has properties. This is the case
3788 // because the global proxy object forwards everything to its hidden
3789 // prototype including local lookups.
3790 //
3791 // Additionally, we need to make sure that we do not cache results
3792 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793 if (args[0]->IsJSObject() &&
3794 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003795 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003796 args[1]->IsString()) {
3797 JSObject* receiver = JSObject::cast(args[0]);
3798 String* key = String::cast(args[1]);
3799 if (receiver->HasFastProperties()) {
3800 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003801 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003802 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3803 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003804 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003805 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003806 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003807 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003808 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003809 LookupResult result;
3810 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003811 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003812 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003813 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003814 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003815 }
3816 } else {
3817 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003818 StringDictionary* dictionary = receiver->property_dictionary();
3819 int entry = dictionary->FindEntry(key);
3820 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003821 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003822 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003823 if (!receiver->IsGlobalObject()) return value;
3824 value = JSGlobalPropertyCell::cast(value)->value();
3825 if (!value->IsTheHole()) return value;
3826 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003827 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003828 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003829 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3830 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003832 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003833 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003834 if (index >= 0 && index < str->length()) {
3835 Handle<Object> result = GetCharAt(str, index);
3836 return *result;
3837 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003838 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003839
3840 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003841 return Runtime::GetObjectProperty(isolate,
3842 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003843 args.at<Object>(1));
3844}
3845
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003846// Implements part of 8.12.9 DefineOwnProperty.
3847// There are 3 cases that lead here:
3848// Step 4b - define a new accessor property.
3849// Steps 9c & 12 - replace an existing data property with an accessor property.
3850// Step 12 - update an existing accessor property with an accessor or generic
3851// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003852RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003853 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003855 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3856 CONVERT_CHECKED(String, name, args[1]);
3857 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003858 Object* fun = args[3];
3859 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003860 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3861 int unchecked = flag_attr->value();
3862 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3863 RUNTIME_ASSERT(!obj->IsNull());
3864 LookupResult result;
3865 obj->LocalLookupRealNamedProperty(name, &result);
3866
3867 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3868 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3869 // delete it to avoid running into trouble in DefineAccessor, which
3870 // handles this incorrectly if the property is readonly (does nothing)
3871 if (result.IsProperty() &&
3872 (result.type() == FIELD || result.type() == NORMAL
3873 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003874 Object* ok;
3875 { MaybeObject* maybe_ok =
3876 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3877 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3878 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003879 }
3880 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3881}
3882
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003883// Implements part of 8.12.9 DefineOwnProperty.
3884// There are 3 cases that lead here:
3885// Step 4a - define a new data property.
3886// Steps 9b & 12 - replace an existing accessor property with a data property.
3887// Step 12 - update an existing data property with a data or generic
3888// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003889RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003890 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003892 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3893 CONVERT_ARG_CHECKED(String, name, 1);
3894 Handle<Object> obj_value = args.at<Object>(2);
3895
3896 CONVERT_CHECKED(Smi, flag, args[3]);
3897 int unchecked = flag->value();
3898 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3899
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003900 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3901
3902 // Check if this is an element.
3903 uint32_t index;
3904 bool is_element = name->AsArrayIndex(&index);
3905
3906 // Special case for elements if any of the flags are true.
3907 // If elements are in fast case we always implicitly assume that:
3908 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3909 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3910 is_element) {
3911 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003912 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003913 // We do not need to do access checks here since these has already
3914 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003915 Handle<Object> proto(js_object->GetPrototype());
3916 // If proxy is detached, ignore the assignment. Alternatively,
3917 // we could throw an exception.
3918 if (proto->IsNull()) return *obj_value;
3919 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003920 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003921 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003922 // Make sure that we never go back to fast case.
3923 dictionary->set_requires_slow_elements();
3924 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003925 Handle<NumberDictionary> extended_dictionary =
3926 NumberDictionarySet(dictionary, index, obj_value, details);
3927 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003928 if (js_object->GetElementsKind() ==
3929 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
3930 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
3931 } else {
3932 js_object->set_elements(*extended_dictionary);
3933 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003934 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003935 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003936 }
3937
ager@chromium.org5c838252010-02-19 08:53:10 +00003938 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003939 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003940
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003941 // To be compatible with safari we do not change the value on API objects
3942 // in defineProperty. Firefox disagrees here, and actually changes the value.
3943 if (result.IsProperty() &&
3944 (result.type() == CALLBACKS) &&
3945 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003947 }
3948
ager@chromium.org5c838252010-02-19 08:53:10 +00003949 // Take special care when attributes are different and there is already
3950 // a property. For simplicity we normalize the property which enables us
3951 // to not worry about changing the instance_descriptor and creating a new
3952 // map. The current version of SetObjectProperty does not handle attributes
3953 // correctly in the case where a property is a field and is reset with
3954 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003955 if (result.IsProperty() &&
3956 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003957 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003958 if (js_object->IsJSGlobalProxy()) {
3959 // Since the result is a property, the prototype will exist so
3960 // we don't have to check for null.
3961 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003962 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003963 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003964 // Use IgnoreAttributes version since a readonly property may be
3965 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003966 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3967 *obj_value,
3968 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003969 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 return Runtime::ForceSetObjectProperty(isolate,
3972 js_object,
3973 name,
3974 obj_value,
3975 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003976}
3977
3978
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003979// Special case for elements if any of the flags are true.
3980// If elements are in fast case we always implicitly assume that:
3981// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3982static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3983 Handle<JSObject> js_object,
3984 uint32_t index,
3985 Handle<Object> value,
3986 PropertyAttributes attr) {
3987 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003988 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003989 // Make sure that we never go back to fast case.
3990 dictionary->set_requires_slow_elements();
3991 PropertyDetails details = PropertyDetails(attr, NORMAL);
3992 Handle<NumberDictionary> extended_dictionary =
3993 NumberDictionarySet(dictionary, index, value, details);
3994 if (*extended_dictionary != *dictionary) {
3995 js_object->set_elements(*extended_dictionary);
3996 }
3997 return *value;
3998}
3999
4000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4002 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004003 Handle<Object> key,
4004 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004005 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004006 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004010 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 isolate->factory()->NewTypeError("non_object_property_store",
4013 HandleVector(args, 2));
4014 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 }
4016
4017 // If the object isn't a JavaScript object, we ignore the store.
4018 if (!object->IsJSObject()) return *value;
4019
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004020 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 // Check if the given key is an array index.
4023 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004024 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4026 // of a string using [] notation. We need to support this too in
4027 // JavaScript.
4028 // In the case of a String object we just need to redirect the assignment to
4029 // the underlying string if the index is in range. Since the underlying
4030 // string does nothing with the assignment then we can ignore such
4031 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004032 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4037 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4038 }
4039
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004040 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 return *value;
4043 }
4044
4045 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004046 Handle<Object> result;
4047 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004048 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4049 return NormalizeObjectSetElement(isolate,
4050 js_object,
4051 index,
4052 value,
4053 attr);
4054 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004055 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004057 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004058 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004059 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004061 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 return *value;
4063 }
4064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 bool has_pending_exception = false;
4067 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4068 if (has_pending_exception) return Failure::Exception();
4069 Handle<String> name = Handle<String>::cast(converted);
4070
4071 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004072 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004074 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
4076}
4077
4078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004079MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4080 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004081 Handle<Object> key,
4082 Handle<Object> value,
4083 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004085
4086 // Check if the given key is an array index.
4087 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004088 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004089 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4090 // of a string using [] notation. We need to support this too in
4091 // JavaScript.
4092 // In the case of a String object we just need to redirect the assignment to
4093 // the underlying string if the index is in range. Since the underlying
4094 // string does nothing with the assignment then we can ignore such
4095 // assignments.
4096 if (js_object->IsStringObjectWithCharacterAt(index)) {
4097 return *value;
4098 }
4099
whesse@chromium.org7b260152011-06-20 15:33:18 +00004100 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004101 }
4102
4103 if (key->IsString()) {
4104 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004105 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004106 } else {
4107 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004108 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004109 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4110 *value,
4111 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004112 }
4113 }
4114
4115 // Call-back into JavaScript to convert the key to a string.
4116 bool has_pending_exception = false;
4117 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4118 if (has_pending_exception) return Failure::Exception();
4119 Handle<String> name = Handle<String>::cast(converted);
4120
4121 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004122 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004123 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004124 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004125 }
4126}
4127
4128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4130 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004131 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004132 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004133
4134 // Check if the given key is an array index.
4135 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004136 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004137 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4138 // characters of a string using [] notation. In the case of a
4139 // String object we just need to redirect the deletion to the
4140 // underlying string if the index is in range. Since the
4141 // underlying string does nothing with the deletion, we can ignore
4142 // such deletions.
4143 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004144 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004145 }
4146
4147 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4148 }
4149
4150 Handle<String> key_string;
4151 if (key->IsString()) {
4152 key_string = Handle<String>::cast(key);
4153 } else {
4154 // Call-back into JavaScript to convert the key to a string.
4155 bool has_pending_exception = false;
4156 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4157 if (has_pending_exception) return Failure::Exception();
4158 key_string = Handle<String>::cast(converted);
4159 }
4160
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004161 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004162 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4163}
4164
4165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004166RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169
4170 Handle<Object> object = args.at<Object>(0);
4171 Handle<Object> key = args.at<Object>(1);
4172 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004173 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004174 RUNTIME_ASSERT(
4175 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004177 PropertyAttributes attributes =
4178 static_cast<PropertyAttributes>(unchecked_attributes);
4179
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004180 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004181 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004182 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004183 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4184 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004185 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004187
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 return Runtime::SetObjectProperty(isolate,
4189 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004190 key,
4191 value,
4192 attributes,
4193 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194}
4195
4196
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004197// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004198// This is used to decide if we should transform null and undefined
4199// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004200RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004201 NoHandleAllocation ha;
4202 RUNTIME_ASSERT(args.length() == 1);
4203
4204 Handle<Object> object = args.at<Object>(0);
4205
4206 if (object->IsJSFunction()) {
4207 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004208 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004209 }
4210 return isolate->heap()->undefined_value();
4211}
4212
4213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214// Set a local property, even if it is READ_ONLY. If the property does not
4215// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004216RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004218 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 CONVERT_CHECKED(JSObject, object, args[0]);
4220 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004221 // Compute attributes.
4222 PropertyAttributes attributes = NONE;
4223 if (args.length() == 4) {
4224 CONVERT_CHECKED(Smi, value_obj, args[3]);
4225 int unchecked_value = value_obj->value();
4226 // Only attribute bits should be set.
4227 RUNTIME_ASSERT(
4228 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4229 attributes = static_cast<PropertyAttributes>(unchecked_value);
4230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004232 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004233 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004234}
4235
4236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004237RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004239 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240
4241 CONVERT_CHECKED(JSObject, object, args[0]);
4242 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004243 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004244 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004245 ? JSObject::STRICT_DELETION
4246 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247}
4248
4249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004250static Object* HasLocalPropertyImplementation(Isolate* isolate,
4251 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004252 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004253 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004254 // Handle hidden prototypes. If there's a hidden prototype above this thing
4255 // then we have to check it for properties, because they are supposed to
4256 // look like they are on this object.
4257 Handle<Object> proto(object->GetPrototype());
4258 if (proto->IsJSObject() &&
4259 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 return HasLocalPropertyImplementation(isolate,
4261 Handle<JSObject>::cast(proto),
4262 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004263 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004264 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004265}
4266
4267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004268RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 NoHandleAllocation ha;
4270 ASSERT(args.length() == 2);
4271 CONVERT_CHECKED(String, key, args[1]);
4272
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004273 uint32_t index;
4274 const bool key_is_array_index = key->AsArrayIndex(&index);
4275
ager@chromium.org9085a012009-05-11 19:22:57 +00004276 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004278 if (obj->IsJSObject()) {
4279 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004280 // Fast case: either the key is a real named property or it is not
4281 // an array index and there are no interceptors or hidden
4282 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004283 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004284 Map* map = object->map();
4285 if (!key_is_array_index &&
4286 !map->has_named_interceptor() &&
4287 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4288 return isolate->heap()->false_value();
4289 }
4290 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 HandleScope scope(isolate);
4292 return HasLocalPropertyImplementation(isolate,
4293 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004294 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004295 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004297 String* string = String::cast(obj);
4298 if (index < static_cast<uint32_t>(string->length())) {
4299 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300 }
4301 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303}
4304
4305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004306RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004307 NoHandleAllocation na;
4308 ASSERT(args.length() == 2);
4309
4310 // Only JS objects can have properties.
4311 if (args[0]->IsJSObject()) {
4312 JSObject* object = JSObject::cast(args[0]);
4313 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004316 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317}
4318
4319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004320RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 NoHandleAllocation na;
4322 ASSERT(args.length() == 2);
4323
4324 // Only JS objects can have elements.
4325 if (args[0]->IsJSObject()) {
4326 JSObject* object = JSObject::cast(args[0]);
4327 CONVERT_CHECKED(Smi, index_obj, args[1]);
4328 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332}
4333
4334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336 NoHandleAllocation ha;
4337 ASSERT(args.length() == 2);
4338
4339 CONVERT_CHECKED(JSObject, object, args[0]);
4340 CONVERT_CHECKED(String, key, args[1]);
4341
4342 uint32_t index;
4343 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004344 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 }
4346
ager@chromium.org870a0b62008-11-04 11:43:05 +00004347 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004348 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004349}
4350
4351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004352RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004353 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004355 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004356 return *GetKeysFor(object);
4357}
4358
4359
4360// Returns either a FixedArray as Runtime_GetPropertyNames,
4361// or, if the given object has an enum cache that contains
4362// all enumerable properties of the object and its prototypes
4363// have none, the map of the object. This is used to speed up
4364// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004366 ASSERT(args.length() == 1);
4367
4368 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4369
4370 if (raw_object->IsSimpleEnum()) return raw_object->map();
4371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004372 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004373 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004374 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4375 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376
4377 // Test again, since cache may have been built by preceding call.
4378 if (object->IsSimpleEnum()) return object->map();
4379
4380 return *content;
4381}
4382
4383
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384// Find the length of the prototype chain that is to to handled as one. If a
4385// prototype object is hidden it is to be viewed as part of the the object it
4386// is prototype for.
4387static int LocalPrototypeChainLength(JSObject* obj) {
4388 int count = 1;
4389 Object* proto = obj->GetPrototype();
4390 while (proto->IsJSObject() &&
4391 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4392 count++;
4393 proto = JSObject::cast(proto)->GetPrototype();
4394 }
4395 return count;
4396}
4397
4398
4399// Return the names of the local named properties.
4400// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004401RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004403 ASSERT(args.length() == 1);
4404 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004406 }
4407 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4408
4409 // Skip the global proxy as it has no properties and always delegates to the
4410 // real global object.
4411 if (obj->IsJSGlobalProxy()) {
4412 // Only collect names if access is permitted.
4413 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 !isolate->MayNamedAccess(*obj,
4415 isolate->heap()->undefined_value(),
4416 v8::ACCESS_KEYS)) {
4417 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4418 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419 }
4420 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4421 }
4422
4423 // Find the number of objects making up this.
4424 int length = LocalPrototypeChainLength(*obj);
4425
4426 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004427 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004428 int total_property_count = 0;
4429 Handle<JSObject> jsproto = obj;
4430 for (int i = 0; i < length; i++) {
4431 // Only collect names if access is permitted.
4432 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 !isolate->MayNamedAccess(*jsproto,
4434 isolate->heap()->undefined_value(),
4435 v8::ACCESS_KEYS)) {
4436 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4437 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004438 }
4439 int n;
4440 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4441 local_property_count[i] = n;
4442 total_property_count += n;
4443 if (i < length - 1) {
4444 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4445 }
4446 }
4447
4448 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 Handle<FixedArray> names =
4450 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004451
4452 // Get the property names.
4453 jsproto = obj;
4454 int proto_with_hidden_properties = 0;
4455 for (int i = 0; i < length; i++) {
4456 jsproto->GetLocalPropertyNames(*names,
4457 i == 0 ? 0 : local_property_count[i - 1]);
4458 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4459 proto_with_hidden_properties++;
4460 }
4461 if (i < length - 1) {
4462 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4463 }
4464 }
4465
4466 // Filter out name of hidden propeties object.
4467 if (proto_with_hidden_properties > 0) {
4468 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004469 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 names->length() - proto_with_hidden_properties);
4471 int dest_pos = 0;
4472 for (int i = 0; i < total_property_count; i++) {
4473 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004474 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004475 continue;
4476 }
4477 names->set(dest_pos++, name);
4478 }
4479 }
4480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004482}
4483
4484
4485// Return the names of the local indexed properties.
4486// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004487RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004488 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004489 ASSERT(args.length() == 1);
4490 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004492 }
4493 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4494
4495 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004497 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004499}
4500
4501
4502// Return information on whether an object has a named or indexed interceptor.
4503// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004504RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004505 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004506 ASSERT(args.length() == 1);
4507 if (!args[0]->IsJSObject()) {
4508 return Smi::FromInt(0);
4509 }
4510 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4511
4512 int result = 0;
4513 if (obj->HasNamedInterceptor()) result |= 2;
4514 if (obj->HasIndexedInterceptor()) result |= 1;
4515
4516 return Smi::FromInt(result);
4517}
4518
4519
4520// Return property names from named interceptor.
4521// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004522RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004523 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004524 ASSERT(args.length() == 1);
4525 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4526
4527 if (obj->HasNamedInterceptor()) {
4528 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4529 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004532}
4533
4534
4535// Return element names from indexed interceptor.
4536// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004537RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004539 ASSERT(args.length() == 1);
4540 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4541
4542 if (obj->HasIndexedInterceptor()) {
4543 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4544 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547}
4548
4549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004550RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004551 ASSERT_EQ(args.length(), 1);
4552 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004554 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004555
4556 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004557 // Do access checks before going to the global object.
4558 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004560 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004561 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4562 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004563 }
4564
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004565 Handle<Object> proto(object->GetPrototype());
4566 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004568 object = Handle<JSObject>::cast(proto);
4569 }
4570
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004571 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4572 LOCAL_ONLY);
4573 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4574 // property array and since the result is mutable we have to create
4575 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004576 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004577 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004578 for (int i = 0; i < length; i++) {
4579 Object* entry = contents->get(i);
4580 if (entry->IsString()) {
4581 copy->set(i, entry);
4582 } else {
4583 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004584 HandleScope scope(isolate);
4585 Handle<Object> entry_handle(entry, isolate);
4586 Handle<Object> entry_str =
4587 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004588 copy->set(i, *entry_str);
4589 }
4590 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004592}
4593
4594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004595RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 NoHandleAllocation ha;
4597 ASSERT(args.length() == 1);
4598
4599 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004600 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 it.AdvanceToArgumentsFrame();
4602 JavaScriptFrame* frame = it.frame();
4603
4604 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004605 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606
4607 // Try to convert the key to an index. If successful and within
4608 // index return the the argument from the frame.
4609 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004610 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 return frame->GetParameter(index);
4612 }
4613
4614 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 bool exception = false;
4617 Handle<Object> converted =
4618 Execution::ToString(args.at<Object>(0), &exception);
4619 if (exception) return Failure::Exception();
4620 Handle<String> key = Handle<String>::cast(converted);
4621
4622 // Try to convert the string key into an array index.
4623 if (key->AsArrayIndex(&index)) {
4624 if (index < n) {
4625 return frame->GetParameter(index);
4626 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 }
4629 }
4630
4631 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4633 if (key->Equals(isolate->heap()->callee_symbol())) {
4634 Object* function = frame->function();
4635 if (function->IsJSFunction() &&
4636 JSFunction::cast(function)->shared()->strict_mode()) {
4637 return isolate->Throw(*isolate->factory()->NewTypeError(
4638 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4639 }
4640 return function;
4641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642
4643 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645}
4646
4647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004650
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004651 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004652 Handle<Object> object = args.at<Object>(0);
4653 if (object->IsJSObject()) {
4654 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004655 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004656 MaybeObject* ok = js_object->TransformToFastProperties(0);
4657 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004658 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004659 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004660 return *object;
4661}
4662
4663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004664RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004665 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004666
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004667 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004668 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004669 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004670 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004671 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004672 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004673 return *object;
4674}
4675
4676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004677RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 NoHandleAllocation ha;
4679 ASSERT(args.length() == 1);
4680
4681 return args[0]->ToBoolean();
4682}
4683
4684
4685// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4686// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
4689
4690 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004691 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 HeapObject* heap_obj = HeapObject::cast(obj);
4693
4694 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 if (heap_obj->map()->is_undetectable()) {
4696 return isolate->heap()->undefined_symbol();
4697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698
4699 InstanceType instance_type = heap_obj->map()->instance_type();
4700 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 }
4703
4704 switch (instance_type) {
4705 case ODDBALL_TYPE:
4706 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 }
4709 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 }
4712 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004714 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716 default:
4717 // For any kind of object not handled above, the spec rule for
4718 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004719 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 }
4721}
4722
4723
lrn@chromium.org25156de2010-04-06 13:10:27 +00004724static bool AreDigits(const char*s, int from, int to) {
4725 for (int i = from; i < to; i++) {
4726 if (s[i] < '0' || s[i] > '9') return false;
4727 }
4728
4729 return true;
4730}
4731
4732
4733static int ParseDecimalInteger(const char*s, int from, int to) {
4734 ASSERT(to - from < 10); // Overflow is not possible.
4735 ASSERT(from < to);
4736 int d = s[from] - '0';
4737
4738 for (int i = from + 1; i < to; i++) {
4739 d = 10 * d + (s[i] - '0');
4740 }
4741
4742 return d;
4743}
4744
4745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004746RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 NoHandleAllocation ha;
4748 ASSERT(args.length() == 1);
4749 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004750 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004751
4752 // Fast case: short integer or some sorts of junk values.
4753 int len = subject->length();
4754 if (subject->IsSeqAsciiString()) {
4755 if (len == 0) return Smi::FromInt(0);
4756
4757 char const* data = SeqAsciiString::cast(subject)->GetChars();
4758 bool minus = (data[0] == '-');
4759 int start_pos = (minus ? 1 : 0);
4760
4761 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004763 } else if (data[start_pos] > '9') {
4764 // Fast check for a junk value. A valid string may start from a
4765 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4766 // the 'I' character ('Infinity'). All of that have codes not greater than
4767 // '9' except 'I'.
4768 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004770 }
4771 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4772 // The maximal/minimal smi has 10 digits. If the string has less digits we
4773 // know it will fit into the smi-data type.
4774 int d = ParseDecimalInteger(data, start_pos, len);
4775 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004777 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004778 } else if (!subject->HasHashCode() &&
4779 len <= String::kMaxArrayIndexSize &&
4780 (len == 1 || data[0] != '0')) {
4781 // String hash is not calculated yet but all the data are present.
4782 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004783 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004784#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004785 subject->Hash(); // Force hash calculation.
4786 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4787 static_cast<int>(hash));
4788#endif
4789 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004790 }
4791 return Smi::FromInt(d);
4792 }
4793 }
4794
4795 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004796 return isolate->heap()->NumberFromDouble(
4797 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798}
4799
4800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004801RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 NoHandleAllocation ha;
4803 ASSERT(args.length() == 1);
4804
4805 CONVERT_CHECKED(JSArray, codes, args[0]);
4806 int length = Smi::cast(codes->length())->value();
4807
4808 // Check if the string can be ASCII.
4809 int i;
4810 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004811 Object* element;
4812 { MaybeObject* maybe_element = codes->GetElement(i);
4813 // We probably can't get an exception here, but just in order to enforce
4814 // the checking of inputs in the runtime calls we check here.
4815 if (!maybe_element->ToObject(&element)) return maybe_element;
4816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4818 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4819 break;
4820 }
4821
lrn@chromium.org303ada72010-10-27 09:33:13 +00004822 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004824 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 }
4828
lrn@chromium.org303ada72010-10-27 09:33:13 +00004829 Object* object = NULL;
4830 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 String* result = String::cast(object);
4832 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004833 Object* element;
4834 { MaybeObject* maybe_element = codes->GetElement(i);
4835 if (!maybe_element->ToObject(&element)) return maybe_element;
4836 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004838 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839 }
4840 return result;
4841}
4842
4843
4844// kNotEscaped is generated by the following:
4845//
4846// #!/bin/perl
4847// for (my $i = 0; $i < 256; $i++) {
4848// print "\n" if $i % 16 == 0;
4849// my $c = chr($i);
4850// my $escaped = 1;
4851// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4852// print $escaped ? "0, " : "1, ";
4853// }
4854
4855
4856static bool IsNotEscaped(uint16_t character) {
4857 // Only for 8 bit characters, the rest are always escaped (in a different way)
4858 ASSERT(character < 256);
4859 static const char kNotEscaped[256] = {
4860 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4861 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4862 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4864 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4865 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4866 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4867 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4872 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4873 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4874 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4875 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4876 };
4877 return kNotEscaped[character] != 0;
4878}
4879
4880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004881RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882 const char hex_chars[] = "0123456789ABCDEF";
4883 NoHandleAllocation ha;
4884 ASSERT(args.length() == 1);
4885 CONVERT_CHECKED(String, source, args[0]);
4886
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004887 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
4889 int escaped_length = 0;
4890 int length = source->length();
4891 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 Access<StringInputBuffer> buffer(
4893 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894 buffer->Reset(source);
4895 while (buffer->has_more()) {
4896 uint16_t character = buffer->GetNext();
4897 if (character >= 256) {
4898 escaped_length += 6;
4899 } else if (IsNotEscaped(character)) {
4900 escaped_length++;
4901 } else {
4902 escaped_length += 3;
4903 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004904 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004905 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004906 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004907 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 return Failure::OutOfMemoryException();
4909 }
4910 }
4911 }
4912 // No length change implies no change. Return original string if no change.
4913 if (escaped_length == length) {
4914 return source;
4915 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 { MaybeObject* maybe_o =
4918 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004919 if (!maybe_o->ToObject(&o)) return maybe_o;
4920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 String* destination = String::cast(o);
4922 int dest_position = 0;
4923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004924 Access<StringInputBuffer> buffer(
4925 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926 buffer->Rewind();
4927 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004928 uint16_t chr = buffer->GetNext();
4929 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004930 destination->Set(dest_position, '%');
4931 destination->Set(dest_position+1, 'u');
4932 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4933 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4934 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4935 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004937 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 dest_position++;
4940 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004941 destination->Set(dest_position, '%');
4942 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4943 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004944 dest_position += 3;
4945 }
4946 }
4947 return destination;
4948}
4949
4950
4951static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4952 static const signed char kHexValue['g'] = {
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4955 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4956 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4957 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4958 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4959 -1, 10, 11, 12, 13, 14, 15 };
4960
4961 if (character1 > 'f') return -1;
4962 int hi = kHexValue[character1];
4963 if (hi == -1) return -1;
4964 if (character2 > 'f') return -1;
4965 int lo = kHexValue[character2];
4966 if (lo == -1) return -1;
4967 return (hi << 4) + lo;
4968}
4969
4970
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004972 int i,
4973 int length,
4974 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004975 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004976 int32_t hi = 0;
4977 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978 if (character == '%' &&
4979 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004980 source->Get(i + 1) == 'u' &&
4981 (hi = TwoDigitHex(source->Get(i + 2),
4982 source->Get(i + 3))) != -1 &&
4983 (lo = TwoDigitHex(source->Get(i + 4),
4984 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 *step = 6;
4986 return (hi << 8) + lo;
4987 } else if (character == '%' &&
4988 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 (lo = TwoDigitHex(source->Get(i + 1),
4990 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004991 *step = 3;
4992 return lo;
4993 } else {
4994 *step = 1;
4995 return character;
4996 }
4997}
4998
4999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005000RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 NoHandleAllocation ha;
5002 ASSERT(args.length() == 1);
5003 CONVERT_CHECKED(String, source, args[0]);
5004
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005005 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006
5007 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005008 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009
5010 int unescaped_length = 0;
5011 for (int i = 0; i < length; unescaped_length++) {
5012 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005013 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005014 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 i += step;
5017 }
5018
5019 // No length change implies no change. Return original string if no change.
5020 if (unescaped_length == length)
5021 return source;
5022
lrn@chromium.org303ada72010-10-27 09:33:13 +00005023 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 { MaybeObject* maybe_o =
5025 ascii ?
5026 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5027 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005028 if (!maybe_o->ToObject(&o)) return maybe_o;
5029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005030 String* destination = String::cast(o);
5031
5032 int dest_position = 0;
5033 for (int i = 0; i < length; dest_position++) {
5034 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005035 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005036 i += step;
5037 }
5038 return destination;
5039}
5040
5041
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042static const unsigned int kQuoteTableLength = 128u;
5043
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005044static const int kJsonQuotesCharactersPerEntry = 8;
5045static const char* const JsonQuotes =
5046 "\\u0000 \\u0001 \\u0002 \\u0003 "
5047 "\\u0004 \\u0005 \\u0006 \\u0007 "
5048 "\\b \\t \\n \\u000b "
5049 "\\f \\r \\u000e \\u000f "
5050 "\\u0010 \\u0011 \\u0012 \\u0013 "
5051 "\\u0014 \\u0015 \\u0016 \\u0017 "
5052 "\\u0018 \\u0019 \\u001a \\u001b "
5053 "\\u001c \\u001d \\u001e \\u001f "
5054 " ! \\\" # "
5055 "$ % & ' "
5056 "( ) * + "
5057 ", - . / "
5058 "0 1 2 3 "
5059 "4 5 6 7 "
5060 "8 9 : ; "
5061 "< = > ? "
5062 "@ A B C "
5063 "D E F G "
5064 "H I J K "
5065 "L M N O "
5066 "P Q R S "
5067 "T U V W "
5068 "X Y Z [ "
5069 "\\\\ ] ^ _ "
5070 "` a b c "
5071 "d e f g "
5072 "h i j k "
5073 "l m n o "
5074 "p q r s "
5075 "t u v w "
5076 "x y z { "
5077 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005078
5079
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080// For a string that is less than 32k characters it should always be
5081// possible to allocate it in new space.
5082static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5083
5084
5085// Doing JSON quoting cannot make the string more than this many times larger.
5086static const int kJsonQuoteWorstCaseBlowup = 6;
5087
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005088static const int kSpaceForQuotesAndComma = 3;
5089static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005090
5091// Covers the entire ASCII range (all other characters are unchanged by JSON
5092// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093static const byte JsonQuoteLengths[kQuoteTableLength] = {
5094 6, 6, 6, 6, 6, 6, 6, 6,
5095 2, 2, 2, 6, 2, 2, 6, 6,
5096 6, 6, 6, 6, 6, 6, 6, 6,
5097 6, 6, 6, 6, 6, 6, 6, 6,
5098 1, 1, 2, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 1, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104 1, 1, 1, 1, 1, 1, 1, 1,
5105 1, 1, 1, 1, 2, 1, 1, 1,
5106 1, 1, 1, 1, 1, 1, 1, 1,
5107 1, 1, 1, 1, 1, 1, 1, 1,
5108 1, 1, 1, 1, 1, 1, 1, 1,
5109 1, 1, 1, 1, 1, 1, 1, 1,
5110};
5111
5112
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005115
5116
5117template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5119 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005120}
5121
5122
5123template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5125 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126}
5127
5128
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005129template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005130static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5131 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005133 const Char* read_cursor = characters.start();
5134 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005135 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005136 int quoted_length = kSpaceForQuotes;
5137 while (read_cursor < end) {
5138 Char c = *(read_cursor++);
5139 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5140 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005141 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005142 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005143 }
5144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5146 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 Object* new_object;
5148 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 return new_alloc;
5150 }
5151 StringType* new_string = StringType::cast(new_object);
5152
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005153 Char* write_cursor = reinterpret_cast<Char*>(
5154 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005155 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005156 *(write_cursor++) = '"';
5157
5158 read_cursor = characters.start();
5159 while (read_cursor < end) {
5160 Char c = *(read_cursor++);
5161 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5162 *(write_cursor++) = c;
5163 } else {
5164 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5165 const char* replacement = JsonQuotes +
5166 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5167 for (int i = 0; i < len; i++) {
5168 *write_cursor++ = *replacement++;
5169 }
5170 }
5171 }
5172 *(write_cursor++) = '"';
5173 return new_string;
5174}
5175
5176
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005177template <typename SinkChar, typename SourceChar>
5178static inline SinkChar* WriteQuoteJsonString(
5179 Isolate* isolate,
5180 SinkChar* write_cursor,
5181 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005182 // SinkChar is only char if SourceChar is guaranteed to be char.
5183 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005184 const SourceChar* read_cursor = characters.start();
5185 const SourceChar* end = read_cursor + characters.length();
5186 *(write_cursor++) = '"';
5187 while (read_cursor < end) {
5188 SourceChar c = *(read_cursor++);
5189 if (sizeof(SourceChar) > 1u &&
5190 static_cast<unsigned>(c) >= kQuoteTableLength) {
5191 *(write_cursor++) = static_cast<SinkChar>(c);
5192 } else {
5193 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5194 const char* replacement = JsonQuotes +
5195 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5196 write_cursor[0] = replacement[0];
5197 if (len > 1) {
5198 write_cursor[1] = replacement[1];
5199 if (len > 2) {
5200 ASSERT(len == 6);
5201 write_cursor[2] = replacement[2];
5202 write_cursor[3] = replacement[3];
5203 write_cursor[4] = replacement[4];
5204 write_cursor[5] = replacement[5];
5205 }
5206 }
5207 write_cursor += len;
5208 }
5209 }
5210 *(write_cursor++) = '"';
5211 return write_cursor;
5212}
5213
5214
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005215template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216static MaybeObject* QuoteJsonString(Isolate* isolate,
5217 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005218 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005220 int worst_case_length =
5221 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005222 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224 }
5225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005226 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5227 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005228 Object* new_object;
5229 if (!new_alloc->ToObject(&new_object)) {
5230 return new_alloc;
5231 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005233 // Even if our string is small enough to fit in new space we still have to
5234 // handle it being allocated in old space as may happen in the third
5235 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5236 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005237 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005238 }
5239 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241
5242 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5243 Char* write_cursor = reinterpret_cast<Char*>(
5244 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005245 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005246 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5247 write_cursor,
5248 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005249 int final_length = static_cast<int>(
5250 write_cursor - reinterpret_cast<Char*>(
5251 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005252 isolate->heap()->new_space()->
5253 template ShrinkStringAtAllocationBoundary<StringType>(
5254 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005255 return new_string;
5256}
5257
5258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005259RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005260 NoHandleAllocation ha;
5261 CONVERT_CHECKED(String, str, args[0]);
5262 if (!str->IsFlat()) {
5263 MaybeObject* try_flatten = str->TryFlatten();
5264 Object* flat;
5265 if (!try_flatten->ToObject(&flat)) {
5266 return try_flatten;
5267 }
5268 str = String::cast(flat);
5269 ASSERT(str->IsFlat());
5270 }
5271 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5273 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5276 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005277 }
5278}
5279
5280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005281RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005282 NoHandleAllocation ha;
5283 CONVERT_CHECKED(String, str, args[0]);
5284 if (!str->IsFlat()) {
5285 MaybeObject* try_flatten = str->TryFlatten();
5286 Object* flat;
5287 if (!try_flatten->ToObject(&flat)) {
5288 return try_flatten;
5289 }
5290 str = String::cast(flat);
5291 ASSERT(str->IsFlat());
5292 }
5293 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5295 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005296 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005297 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5298 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005299 }
5300}
5301
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005302
5303template <typename Char, typename StringType>
5304static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5305 FixedArray* array,
5306 int worst_case_length) {
5307 int length = array->length();
5308
5309 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5310 worst_case_length);
5311 Object* new_object;
5312 if (!new_alloc->ToObject(&new_object)) {
5313 return new_alloc;
5314 }
5315 if (!isolate->heap()->new_space()->Contains(new_object)) {
5316 // Even if our string is small enough to fit in new space we still have to
5317 // handle it being allocated in old space as may happen in the third
5318 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5319 // CEntryStub::GenerateCore.
5320 return isolate->heap()->undefined_value();
5321 }
5322 AssertNoAllocation no_gc;
5323 StringType* new_string = StringType::cast(new_object);
5324 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5325
5326 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5327 Char* write_cursor = reinterpret_cast<Char*>(
5328 new_string->address() + SeqAsciiString::kHeaderSize);
5329 *(write_cursor++) = '[';
5330 for (int i = 0; i < length; i++) {
5331 if (i != 0) *(write_cursor++) = ',';
5332 String* str = String::cast(array->get(i));
5333 if (str->IsTwoByteRepresentation()) {
5334 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5335 write_cursor,
5336 str->ToUC16Vector());
5337 } else {
5338 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5339 write_cursor,
5340 str->ToAsciiVector());
5341 }
5342 }
5343 *(write_cursor++) = ']';
5344
5345 int final_length = static_cast<int>(
5346 write_cursor - reinterpret_cast<Char*>(
5347 new_string->address() + SeqAsciiString::kHeaderSize));
5348 isolate->heap()->new_space()->
5349 template ShrinkStringAtAllocationBoundary<StringType>(
5350 new_string, final_length);
5351 return new_string;
5352}
5353
5354
5355RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5356 NoHandleAllocation ha;
5357 ASSERT(args.length() == 1);
5358 CONVERT_CHECKED(JSArray, array, args[0]);
5359
5360 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5361 FixedArray* elements = FixedArray::cast(array->elements());
5362 int n = elements->length();
5363 bool ascii = true;
5364 int total_length = 0;
5365
5366 for (int i = 0; i < n; i++) {
5367 Object* elt = elements->get(i);
5368 if (!elt->IsString()) return isolate->heap()->undefined_value();
5369 String* element = String::cast(elt);
5370 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5371 total_length += element->length();
5372 if (ascii && element->IsTwoByteRepresentation()) {
5373 ascii = false;
5374 }
5375 }
5376
5377 int worst_case_length =
5378 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5379 + total_length * kJsonQuoteWorstCaseBlowup;
5380
5381 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5382 return isolate->heap()->undefined_value();
5383 }
5384
5385 if (ascii) {
5386 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5387 elements,
5388 worst_case_length);
5389 } else {
5390 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5391 elements,
5392 worst_case_length);
5393 }
5394}
5395
5396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005397RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 NoHandleAllocation ha;
5399
5400 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005401 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005403 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404
lrn@chromium.org25156de2010-04-06 13:10:27 +00005405 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005406 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005407 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408}
5409
5410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005411RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 NoHandleAllocation ha;
5413 CONVERT_CHECKED(String, str, args[0]);
5414
5415 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005416 double value = StringToDouble(isolate->unicode_cache(),
5417 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418
5419 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421}
5422
5423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005425MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005426 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 String* s,
5428 int length,
5429 int input_string_length,
5430 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 // We try this twice, once with the assumption that the result is no longer
5432 // than the input and, if that assumption breaks, again with the exact
5433 // length. This may not be pretty, but it is nicer than what was here before
5434 // and I hereby claim my vaffel-is.
5435 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005436 // Allocate the resulting string.
5437 //
5438 // NOTE: This assumes that the upper/lower case of an ascii
5439 // character is also ascii. This is currently the case, but it
5440 // might break in the future if we implement more context and locale
5441 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005442 Object* o;
5443 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 ? isolate->heap()->AllocateRawAsciiString(length)
5445 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005446 if (!maybe_o->ToObject(&o)) return maybe_o;
5447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 String* result = String::cast(o);
5449 bool has_changed_character = false;
5450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 // Convert all characters to upper case, assuming that they will fit
5452 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005453 Access<StringInputBuffer> buffer(
5454 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005456 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 // We can assume that the string is not empty
5458 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005460 bool has_next = buffer->has_more();
5461 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005462 int char_length = mapping->get(current, next, chars);
5463 if (char_length == 0) {
5464 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005465 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 i++;
5467 } else if (char_length == 1) {
5468 // Common case: converting the letter resulted in one character.
5469 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005470 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 has_changed_character = true;
5472 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 // We've assumed that the result would be as long as the
5475 // input but here is a character that converts to several
5476 // characters. No matter, we calculate the exact length
5477 // of the result and try the whole thing again.
5478 //
5479 // Note that this leaves room for optimization. We could just
5480 // memcpy what we already have to the result string. Also,
5481 // the result string is the last object allocated we could
5482 // "realloc" it and probably, in the vast majority of cases,
5483 // extend the existing string to be able to hold the full
5484 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005485 int next_length = 0;
5486 if (has_next) {
5487 next_length = mapping->get(next, 0, chars);
5488 if (next_length == 0) next_length = 1;
5489 }
5490 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 while (buffer->has_more()) {
5492 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005493 // NOTE: we use 0 as the next character here because, while
5494 // the next character may affect what a character converts to,
5495 // it does not in any case affect the length of what it convert
5496 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 int char_length = mapping->get(current, 0, chars);
5498 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005499 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005501 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 return Failure::OutOfMemoryException();
5503 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005505 // Try again with the real length.
5506 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 } else {
5508 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 i++;
5511 }
5512 has_changed_character = true;
5513 }
5514 current = next;
5515 }
5516 if (has_changed_character) {
5517 return result;
5518 } else {
5519 // If we didn't actually change anything in doing the conversion
5520 // we simple return the result and let the converted string
5521 // become garbage; there is no reason to keep two identical strings
5522 // alive.
5523 return s;
5524 }
5525}
5526
5527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005528namespace {
5529
lrn@chromium.org303ada72010-10-27 09:33:13 +00005530static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5531
5532
5533// Given a word and two range boundaries returns a word with high bit
5534// set in every byte iff the corresponding input byte was strictly in
5535// the range (m, n). All the other bits in the result are cleared.
5536// This function is only useful when it can be inlined and the
5537// boundaries are statically known.
5538// Requires: all bytes in the input word and the boundaries must be
5539// ascii (less than 0x7F).
5540static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5541 // Every byte in an ascii string is less than or equal to 0x7F.
5542 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5543 // Use strict inequalities since in edge cases the function could be
5544 // further simplified.
5545 ASSERT(0 < m && m < n && n < 0x7F);
5546 // Has high bit set in every w byte less than n.
5547 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5548 // Has high bit set in every w byte greater than m.
5549 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5550 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5551}
5552
5553
5554enum AsciiCaseConversion {
5555 ASCII_TO_LOWER,
5556 ASCII_TO_UPPER
5557};
5558
5559
5560template <AsciiCaseConversion dir>
5561struct FastAsciiConverter {
5562 static bool Convert(char* dst, char* src, int length) {
5563#ifdef DEBUG
5564 char* saved_dst = dst;
5565 char* saved_src = src;
5566#endif
5567 // We rely on the distance between upper and lower case letters
5568 // being a known power of 2.
5569 ASSERT('a' - 'A' == (1 << 5));
5570 // Boundaries for the range of input characters than require conversion.
5571 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5572 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5573 bool changed = false;
5574 char* const limit = src + length;
5575#ifdef V8_HOST_CAN_READ_UNALIGNED
5576 // Process the prefix of the input that requires no conversion one
5577 // (machine) word at a time.
5578 while (src <= limit - sizeof(uintptr_t)) {
5579 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5580 if (AsciiRangeMask(w, lo, hi) != 0) {
5581 changed = true;
5582 break;
5583 }
5584 *reinterpret_cast<uintptr_t*>(dst) = w;
5585 src += sizeof(uintptr_t);
5586 dst += sizeof(uintptr_t);
5587 }
5588 // Process the remainder of the input performing conversion when
5589 // required one word at a time.
5590 while (src <= limit - sizeof(uintptr_t)) {
5591 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5592 uintptr_t m = AsciiRangeMask(w, lo, hi);
5593 // The mask has high (7th) bit set in every byte that needs
5594 // conversion and we know that the distance between cases is
5595 // 1 << 5.
5596 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5597 src += sizeof(uintptr_t);
5598 dst += sizeof(uintptr_t);
5599 }
5600#endif
5601 // Process the last few bytes of the input (or the whole input if
5602 // unaligned access is not supported).
5603 while (src < limit) {
5604 char c = *src;
5605 if (lo < c && c < hi) {
5606 c ^= (1 << 5);
5607 changed = true;
5608 }
5609 *dst = c;
5610 ++src;
5611 ++dst;
5612 }
5613#ifdef DEBUG
5614 CheckConvert(saved_dst, saved_src, length, changed);
5615#endif
5616 return changed;
5617 }
5618
5619#ifdef DEBUG
5620 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5621 bool expected_changed = false;
5622 for (int i = 0; i < length; i++) {
5623 if (dst[i] == src[i]) continue;
5624 expected_changed = true;
5625 if (dir == ASCII_TO_LOWER) {
5626 ASSERT('A' <= src[i] && src[i] <= 'Z');
5627 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5628 } else {
5629 ASSERT(dir == ASCII_TO_UPPER);
5630 ASSERT('a' <= src[i] && src[i] <= 'z');
5631 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5632 }
5633 }
5634 ASSERT(expected_changed == changed);
5635 }
5636#endif
5637};
5638
5639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005640struct ToLowerTraits {
5641 typedef unibrow::ToLowercase UnibrowConverter;
5642
lrn@chromium.org303ada72010-10-27 09:33:13 +00005643 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005644};
5645
5646
5647struct ToUpperTraits {
5648 typedef unibrow::ToUppercase UnibrowConverter;
5649
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005651};
5652
5653} // namespace
5654
5655
5656template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005657MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005658 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005659 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005660 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005662 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005663 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005664
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005665 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005666 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005667 if (length == 0) return s;
5668
5669 // Simpler handling of ascii strings.
5670 //
5671 // NOTE: This assumes that the upper/lower case of an ascii
5672 // character is also ascii. This is currently the case, but it
5673 // might break in the future if we implement more context and locale
5674 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005675 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678 if (!maybe_o->ToObject(&o)) return maybe_o;
5679 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005681 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005682 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683 return has_changed_character ? result : s;
5684 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005685
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005687 { MaybeObject* maybe_answer =
5688 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5690 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005691 if (answer->IsSmi()) {
5692 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005693 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 ConvertCaseHelper(isolate,
5695 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005696 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5697 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005698 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005699 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005700}
5701
5702
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005703RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005704 return ConvertCase<ToLowerTraits>(
5705 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706}
5707
5708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005709RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 return ConvertCase<ToUpperTraits>(
5711 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005712}
5713
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005714
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005715static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5716 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5717}
5718
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005720RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005721 NoHandleAllocation ha;
5722 ASSERT(args.length() == 3);
5723
5724 CONVERT_CHECKED(String, s, args[0]);
5725 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5726 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5727
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005728 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005729 int length = s->length();
5730
5731 int left = 0;
5732 if (trimLeft) {
5733 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5734 left++;
5735 }
5736 }
5737
5738 int right = length;
5739 if (trimRight) {
5740 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5741 right--;
5742 }
5743 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005744 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005745}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005747
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005748void FindAsciiStringIndices(Vector<const char> subject,
5749 char pattern,
5750 ZoneList<int>* indices,
5751 unsigned int limit) {
5752 ASSERT(limit > 0);
5753 // Collect indices of pattern in subject using memchr.
5754 // Stop after finding at most limit values.
5755 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5756 const char* subject_end = subject_start + subject.length();
5757 const char* pos = subject_start;
5758 while (limit > 0) {
5759 pos = reinterpret_cast<const char*>(
5760 memchr(pos, pattern, subject_end - pos));
5761 if (pos == NULL) return;
5762 indices->Add(static_cast<int>(pos - subject_start));
5763 pos++;
5764 limit--;
5765 }
5766}
5767
5768
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005769template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005770void FindStringIndices(Isolate* isolate,
5771 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005772 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005773 ZoneList<int>* indices,
5774 unsigned int limit) {
5775 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005776 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005777 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005778 int pattern_length = pattern.length();
5779 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005780 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005781 while (limit > 0) {
5782 index = search.Search(subject, index);
5783 if (index < 0) return;
5784 indices->Add(index);
5785 index += pattern_length;
5786 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005787 }
5788}
5789
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005791RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005792 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005794 CONVERT_ARG_CHECKED(String, subject, 0);
5795 CONVERT_ARG_CHECKED(String, pattern, 1);
5796 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5797
5798 int subject_length = subject->length();
5799 int pattern_length = pattern->length();
5800 RUNTIME_ASSERT(pattern_length > 0);
5801
5802 // The limit can be very large (0xffffffffu), but since the pattern
5803 // isn't empty, we can never create more parts than ~half the length
5804 // of the subject.
5805
5806 if (!subject->IsFlat()) FlattenString(subject);
5807
5808 static const int kMaxInitialListCapacity = 16;
5809
danno@chromium.org40cb8782011-05-25 07:58:50 +00005810 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005811
5812 // Find (up to limit) indices of separator and end-of-string in subject
5813 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5814 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005815 if (!pattern->IsFlat()) FlattenString(pattern);
5816
5817 // No allocation block.
5818 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005819 AssertNoAllocation nogc;
5820 if (subject->IsAsciiRepresentation()) {
5821 Vector<const char> subject_vector = subject->ToAsciiVector();
5822 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005823 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5824 if (pattern_vector.length() == 1) {
5825 FindAsciiStringIndices(subject_vector,
5826 pattern_vector[0],
5827 &indices,
5828 limit);
5829 } else {
5830 FindStringIndices(isolate,
5831 subject_vector,
5832 pattern_vector,
5833 &indices,
5834 limit);
5835 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 FindStringIndices(isolate,
5838 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005839 pattern->ToUC16Vector(),
5840 &indices,
5841 limit);
5842 }
5843 } else {
5844 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5845 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005846 FindStringIndices(isolate,
5847 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005848 pattern->ToAsciiVector(),
5849 &indices,
5850 limit);
5851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 FindStringIndices(isolate,
5853 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005854 pattern->ToUC16Vector(),
5855 &indices,
5856 limit);
5857 }
5858 }
5859 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005860
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005861 if (static_cast<uint32_t>(indices.length()) < limit) {
5862 indices.Add(subject_length);
5863 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005864
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005865 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005866
5867 // Create JSArray of substrings separated by separator.
5868 int part_count = indices.length();
5869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005871 result->set_length(Smi::FromInt(part_count));
5872
5873 ASSERT(result->HasFastElements());
5874
5875 if (part_count == 1 && indices.at(0) == subject_length) {
5876 FixedArray::cast(result->elements())->set(0, *subject);
5877 return *result;
5878 }
5879
5880 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5881 int part_start = 0;
5882 for (int i = 0; i < part_count; i++) {
5883 HandleScope local_loop_handle;
5884 int part_end = indices.at(i);
5885 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005886 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005887 elements->set(i, *substring);
5888 part_start = part_end + pattern_length;
5889 }
5890
5891 return *result;
5892}
5893
5894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005895// Copies ascii characters to the given fixed array looking up
5896// one-char strings in the cache. Gives up on the first char that is
5897// not in the cache and fills the remainder with smi zeros. Returns
5898// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899static int CopyCachedAsciiCharsToArray(Heap* heap,
5900 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005901 FixedArray* elements,
5902 int length) {
5903 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005904 FixedArray* ascii_cache = heap->single_character_string_cache();
5905 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005906 int i;
5907 for (i = 0; i < length; ++i) {
5908 Object* value = ascii_cache->get(chars[i]);
5909 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005911 elements->set(i, value, SKIP_WRITE_BARRIER);
5912 }
5913 if (i < length) {
5914 ASSERT(Smi::FromInt(0) == 0);
5915 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5916 }
5917#ifdef DEBUG
5918 for (int j = 0; j < length; ++j) {
5919 Object* element = elements->get(j);
5920 ASSERT(element == Smi::FromInt(0) ||
5921 (element->IsString() && String::cast(element)->LooksValid()));
5922 }
5923#endif
5924 return i;
5925}
5926
5927
5928// Converts a String to JSArray.
5929// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005930RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005932 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005934 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005935
5936 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005937 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005938
5939 Handle<FixedArray> elements;
5940 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 { MaybeObject* maybe_obj =
5943 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005944 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005947
5948 Vector<const char> chars = s->ToAsciiVector();
5949 // Note, this will initialize all elements (not only the prefix)
5950 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005951 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5952 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005953 *elements,
5954 length);
5955
5956 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005957 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5958 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005959 }
5960 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005961 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005962 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005963 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5964 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005965 }
5966 }
5967
5968#ifdef DEBUG
5969 for (int i = 0; i < length; ++i) {
5970 ASSERT(String::cast(elements->get(i))->length() == 1);
5971 }
5972#endif
5973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005975}
5976
5977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005978RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 1);
5981 CONVERT_CHECKED(String, value, args[0]);
5982 return value->ToObject();
5983}
5984
5985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005987 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005989 return char_length == 0;
5990}
5991
5992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005993RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 NoHandleAllocation ha;
5995 ASSERT(args.length() == 1);
5996
5997 Object* number = args[0];
5998 RUNTIME_ASSERT(number->IsNumber());
5999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001}
6002
6003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006004RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006005 NoHandleAllocation ha;
6006 ASSERT(args.length() == 1);
6007
6008 Object* number = args[0];
6009 RUNTIME_ASSERT(number->IsNumber());
6010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006011 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006012}
6013
6014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006015RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006016 NoHandleAllocation ha;
6017 ASSERT(args.length() == 1);
6018
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006019 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006020
6021 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6022 if (number > 0 && number <= Smi::kMaxValue) {
6023 return Smi::FromInt(static_cast<int>(number));
6024 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026}
6027
6028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006029RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006030 NoHandleAllocation ha;
6031 ASSERT(args.length() == 1);
6032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006033 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006034
6035 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6036 if (number > 0 && number <= Smi::kMaxValue) {
6037 return Smi::FromInt(static_cast<int>(number));
6038 }
6039
6040 double double_value = DoubleToInteger(number);
6041 // Map both -0 and +0 to +0.
6042 if (double_value == 0) double_value = 0;
6043
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006045}
6046
6047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 NoHandleAllocation ha;
6050 ASSERT(args.length() == 1);
6051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054}
6055
6056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058 NoHandleAllocation ha;
6059 ASSERT(args.length() == 1);
6060
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006061 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006062
6063 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6064 if (number > 0 && number <= Smi::kMaxValue) {
6065 return Smi::FromInt(static_cast<int>(number));
6066 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068}
6069
6070
ager@chromium.org870a0b62008-11-04 11:43:05 +00006071// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6072// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006073RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006074 NoHandleAllocation ha;
6075 ASSERT(args.length() == 1);
6076
6077 Object* obj = args[0];
6078 if (obj->IsSmi()) {
6079 return obj;
6080 }
6081 if (obj->IsHeapNumber()) {
6082 double value = HeapNumber::cast(obj)->value();
6083 int int_value = FastD2I(value);
6084 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6085 return Smi::FromInt(int_value);
6086 }
6087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006089}
6090
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006092RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006093 NoHandleAllocation ha;
6094 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006096}
6097
6098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006099RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100 NoHandleAllocation ha;
6101 ASSERT(args.length() == 2);
6102
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006103 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6104 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106}
6107
6108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006110 NoHandleAllocation ha;
6111 ASSERT(args.length() == 2);
6112
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006113 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6114 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116}
6117
6118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006120 NoHandleAllocation ha;
6121 ASSERT(args.length() == 2);
6122
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006123 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6124 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006125 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126}
6127
6128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130 NoHandleAllocation ha;
6131 ASSERT(args.length() == 1);
6132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006133 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135}
6136
6137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006138RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006139 NoHandleAllocation ha;
6140 ASSERT(args.length() == 0);
6141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006142 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006143}
6144
6145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006146RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006147 NoHandleAllocation ha;
6148 ASSERT(args.length() == 2);
6149
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006150 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6151 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006152 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153}
6154
6155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006156RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006157 NoHandleAllocation ha;
6158 ASSERT(args.length() == 2);
6159
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006160 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6161 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162
ager@chromium.org3811b432009-10-28 14:53:37 +00006163 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006164 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006166}
6167
6168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006169RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 NoHandleAllocation ha;
6171 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 CONVERT_CHECKED(String, str1, args[0]);
6173 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 isolate->counters()->string_add_runtime()->Increment();
6175 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006176}
6177
6178
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006179template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006180static inline void StringBuilderConcatHelper(String* special,
6181 sinkchar* sink,
6182 FixedArray* fixed_array,
6183 int array_length) {
6184 int position = 0;
6185 for (int i = 0; i < array_length; i++) {
6186 Object* element = fixed_array->get(i);
6187 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006188 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006190 int pos;
6191 int len;
6192 if (encoded_slice > 0) {
6193 // Position and length encoded in one smi.
6194 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6195 len = StringBuilderSubstringLength::decode(encoded_slice);
6196 } else {
6197 // Position and length encoded in two smis.
6198 Object* obj = fixed_array->get(++i);
6199 ASSERT(obj->IsSmi());
6200 pos = Smi::cast(obj)->value();
6201 len = -encoded_slice;
6202 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006203 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006204 sink + position,
6205 pos,
6206 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006207 position += len;
6208 } else {
6209 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006210 int element_length = string->length();
6211 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006212 position += element_length;
6213 }
6214 }
6215}
6216
6217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006218RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006220 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006222 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006224 return Failure::OutOfMemoryException();
6225 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006226 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006227 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006228
6229 // This assumption is used by the slice encoding in one or two smis.
6230 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6231
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006232 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235 }
6236 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006237 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240
6241 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243 } else if (array_length == 1) {
6244 Object* first = fixed_array->get(0);
6245 if (first->IsString()) return first;
6246 }
6247
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006248 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249 int position = 0;
6250 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006251 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 Object* elt = fixed_array->get(i);
6253 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006254 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006255 int smi_value = Smi::cast(elt)->value();
6256 int pos;
6257 int len;
6258 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006259 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006260 pos = StringBuilderSubstringPosition::decode(smi_value);
6261 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006262 } else {
6263 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006264 len = -smi_value;
6265 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006266 i++;
6267 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006269 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006270 Object* next_smi = fixed_array->get(i);
6271 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006272 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006273 }
6274 pos = Smi::cast(next_smi)->value();
6275 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006279 ASSERT(pos >= 0);
6280 ASSERT(len >= 0);
6281 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006282 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006283 }
6284 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006285 } else if (elt->IsString()) {
6286 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006287 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006288 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006289 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006291 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006293 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006295 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006296 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006297 return Failure::OutOfMemoryException();
6298 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006299 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300 }
6301
6302 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006305 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 { MaybeObject* maybe_object =
6307 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006308 if (!maybe_object->ToObject(&object)) return maybe_object;
6309 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006310 SeqAsciiString* answer = SeqAsciiString::cast(object);
6311 StringBuilderConcatHelper(special,
6312 answer->GetChars(),
6313 fixed_array,
6314 array_length);
6315 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006317 { MaybeObject* maybe_object =
6318 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006319 if (!maybe_object->ToObject(&object)) return maybe_object;
6320 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006321 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6322 StringBuilderConcatHelper(special,
6323 answer->GetChars(),
6324 fixed_array,
6325 array_length);
6326 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006328}
6329
6330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006331RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006332 NoHandleAllocation ha;
6333 ASSERT(args.length() == 3);
6334 CONVERT_CHECKED(JSArray, array, args[0]);
6335 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006337 return Failure::OutOfMemoryException();
6338 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006339 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006340 CONVERT_CHECKED(String, separator, args[2]);
6341
6342 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006344 }
6345 FixedArray* fixed_array = FixedArray::cast(array->elements());
6346 if (fixed_array->length() < array_length) {
6347 array_length = fixed_array->length();
6348 }
6349
6350 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006352 } else if (array_length == 1) {
6353 Object* first = fixed_array->get(0);
6354 if (first->IsString()) return first;
6355 }
6356
6357 int separator_length = separator->length();
6358 int max_nof_separators =
6359 (String::kMaxLength + separator_length - 1) / separator_length;
6360 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006361 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006362 return Failure::OutOfMemoryException();
6363 }
6364 int length = (array_length - 1) * separator_length;
6365 for (int i = 0; i < array_length; i++) {
6366 Object* element_obj = fixed_array->get(i);
6367 if (!element_obj->IsString()) {
6368 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006370 }
6371 String* element = String::cast(element_obj);
6372 int increment = element->length();
6373 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006375 return Failure::OutOfMemoryException();
6376 }
6377 length += increment;
6378 }
6379
6380 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006381 { MaybeObject* maybe_object =
6382 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006383 if (!maybe_object->ToObject(&object)) return maybe_object;
6384 }
6385 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6386
6387 uc16* sink = answer->GetChars();
6388#ifdef DEBUG
6389 uc16* end = sink + length;
6390#endif
6391
6392 String* first = String::cast(fixed_array->get(0));
6393 int first_length = first->length();
6394 String::WriteToFlat(first, sink, 0, first_length);
6395 sink += first_length;
6396
6397 for (int i = 1; i < array_length; i++) {
6398 ASSERT(sink + separator_length <= end);
6399 String::WriteToFlat(separator, sink, 0, separator_length);
6400 sink += separator_length;
6401
6402 String* element = String::cast(fixed_array->get(i));
6403 int element_length = element->length();
6404 ASSERT(sink + element_length <= end);
6405 String::WriteToFlat(element, sink, 0, element_length);
6406 sink += element_length;
6407 }
6408 ASSERT(sink == end);
6409
6410 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6411 return answer;
6412}
6413
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006414template <typename Char>
6415static void JoinSparseArrayWithSeparator(FixedArray* elements,
6416 int elements_length,
6417 uint32_t array_length,
6418 String* separator,
6419 Vector<Char> buffer) {
6420 int previous_separator_position = 0;
6421 int separator_length = separator->length();
6422 int cursor = 0;
6423 for (int i = 0; i < elements_length; i += 2) {
6424 int position = NumberToInt32(elements->get(i));
6425 String* string = String::cast(elements->get(i + 1));
6426 int string_length = string->length();
6427 if (string->length() > 0) {
6428 while (previous_separator_position < position) {
6429 String::WriteToFlat<Char>(separator, &buffer[cursor],
6430 0, separator_length);
6431 cursor += separator_length;
6432 previous_separator_position++;
6433 }
6434 String::WriteToFlat<Char>(string, &buffer[cursor],
6435 0, string_length);
6436 cursor += string->length();
6437 }
6438 }
6439 if (separator_length > 0) {
6440 // Array length must be representable as a signed 32-bit number,
6441 // otherwise the total string length would have been too large.
6442 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6443 int last_array_index = static_cast<int>(array_length - 1);
6444 while (previous_separator_position < last_array_index) {
6445 String::WriteToFlat<Char>(separator, &buffer[cursor],
6446 0, separator_length);
6447 cursor += separator_length;
6448 previous_separator_position++;
6449 }
6450 }
6451 ASSERT(cursor <= buffer.length());
6452}
6453
6454
6455RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6456 NoHandleAllocation ha;
6457 ASSERT(args.length() == 3);
6458 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6459 RUNTIME_ASSERT(elements_array->HasFastElements());
6460 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6461 CONVERT_CHECKED(String, separator, args[2]);
6462 // elements_array is fast-mode JSarray of alternating positions
6463 // (increasing order) and strings.
6464 // array_length is length of original array (used to add separators);
6465 // separator is string to put between elements. Assumed to be non-empty.
6466
6467 // Find total length of join result.
6468 int string_length = 0;
6469 bool is_ascii = true;
6470 int max_string_length = SeqAsciiString::kMaxLength;
6471 bool overflow = false;
6472 CONVERT_NUMBER_CHECKED(int, elements_length,
6473 Int32, elements_array->length());
6474 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6475 FixedArray* elements = FixedArray::cast(elements_array->elements());
6476 for (int i = 0; i < elements_length; i += 2) {
6477 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6478 CONVERT_CHECKED(String, string, elements->get(i + 1));
6479 int length = string->length();
6480 if (is_ascii && !string->IsAsciiRepresentation()) {
6481 is_ascii = false;
6482 max_string_length = SeqTwoByteString::kMaxLength;
6483 }
6484 if (length > max_string_length ||
6485 max_string_length - length < string_length) {
6486 overflow = true;
6487 break;
6488 }
6489 string_length += length;
6490 }
6491 int separator_length = separator->length();
6492 if (!overflow && separator_length > 0) {
6493 if (array_length <= 0x7fffffffu) {
6494 int separator_count = static_cast<int>(array_length) - 1;
6495 int remaining_length = max_string_length - string_length;
6496 if ((remaining_length / separator_length) >= separator_count) {
6497 string_length += separator_length * (array_length - 1);
6498 } else {
6499 // Not room for the separators within the maximal string length.
6500 overflow = true;
6501 }
6502 } else {
6503 // Nonempty separator and at least 2^31-1 separators necessary
6504 // means that the string is too large to create.
6505 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6506 overflow = true;
6507 }
6508 }
6509 if (overflow) {
6510 // Throw OutOfMemory exception for creating too large a string.
6511 V8::FatalProcessOutOfMemory("Array join result too large.");
6512 }
6513
6514 if (is_ascii) {
6515 MaybeObject* result_allocation =
6516 isolate->heap()->AllocateRawAsciiString(string_length);
6517 if (result_allocation->IsFailure()) return result_allocation;
6518 SeqAsciiString* result_string =
6519 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6520 JoinSparseArrayWithSeparator<char>(elements,
6521 elements_length,
6522 array_length,
6523 separator,
6524 Vector<char>(result_string->GetChars(),
6525 string_length));
6526 return result_string;
6527 } else {
6528 MaybeObject* result_allocation =
6529 isolate->heap()->AllocateRawTwoByteString(string_length);
6530 if (result_allocation->IsFailure()) return result_allocation;
6531 SeqTwoByteString* result_string =
6532 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6533 JoinSparseArrayWithSeparator<uc16>(elements,
6534 elements_length,
6535 array_length,
6536 separator,
6537 Vector<uc16>(result_string->GetChars(),
6538 string_length));
6539 return result_string;
6540 }
6541}
6542
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 2);
6547
6548 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6549 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006550 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551}
6552
6553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006554RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006555 NoHandleAllocation ha;
6556 ASSERT(args.length() == 2);
6557
6558 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6559 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561}
6562
6563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006564RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 NoHandleAllocation ha;
6566 ASSERT(args.length() == 2);
6567
6568 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6569 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006570 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571}
6572
6573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006574RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 1);
6577
6578 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006579 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580}
6581
6582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 2);
6586
6587 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6588 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590}
6591
6592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006593RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 2);
6596
6597 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6598 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
6606
6607 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6608 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610}
6611
6612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006613RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 NoHandleAllocation ha;
6615 ASSERT(args.length() == 2);
6616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6618 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6620 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6621 if (x == y) return Smi::FromInt(EQUAL);
6622 Object* result;
6623 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6624 result = Smi::FromInt(EQUAL);
6625 } else {
6626 result = Smi::FromInt(NOT_EQUAL);
6627 }
6628 return result;
6629}
6630
6631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006632RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 NoHandleAllocation ha;
6634 ASSERT(args.length() == 2);
6635
6636 CONVERT_CHECKED(String, x, args[0]);
6637 CONVERT_CHECKED(String, y, args[1]);
6638
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639 bool not_equal = !x->Equals(y);
6640 // This is slightly convoluted because the value that signifies
6641 // equality is 0 and inequality is 1 so we have to negate the result
6642 // from String::Equals.
6643 ASSERT(not_equal == 0 || not_equal == 1);
6644 STATIC_CHECK(EQUAL == 0);
6645 STATIC_CHECK(NOT_EQUAL == 1);
6646 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647}
6648
6649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006650RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651 NoHandleAllocation ha;
6652 ASSERT(args.length() == 3);
6653
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006654 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6655 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 if (isnan(x) || isnan(y)) return args[2];
6657 if (x == y) return Smi::FromInt(EQUAL);
6658 if (isless(x, y)) return Smi::FromInt(LESS);
6659 return Smi::FromInt(GREATER);
6660}
6661
6662
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006663// Compare two Smis as if they were converted to strings and then
6664// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006666 NoHandleAllocation ha;
6667 ASSERT(args.length() == 2);
6668
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006669 // Extract the integer values from the Smis.
6670 CONVERT_CHECKED(Smi, x, args[0]);
6671 CONVERT_CHECKED(Smi, y, args[1]);
6672 int x_value = x->value();
6673 int y_value = y->value();
6674
6675 // If the integers are equal so are the string representations.
6676 if (x_value == y_value) return Smi::FromInt(EQUAL);
6677
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006678 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006679 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006680 if (x_value == 0 || y_value == 0)
6681 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006682
ager@chromium.org32912102009-01-16 10:38:43 +00006683 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006684 // smallest because the char code of '-' is less than the char code
6685 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006686
6687 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6688 // architectures using 32-bit Smis.
6689 uint32_t x_scaled = x_value;
6690 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006691 if (x_value < 0 || y_value < 0) {
6692 if (y_value >= 0) return Smi::FromInt(LESS);
6693 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006694 x_scaled = -x_value;
6695 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006696 }
6697
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006698 static const uint32_t kPowersOf10[] = {
6699 1, 10, 100, 1000, 10*1000, 100*1000,
6700 1000*1000, 10*1000*1000, 100*1000*1000,
6701 1000*1000*1000
6702 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006704 // If the integers have the same number of decimal digits they can be
6705 // compared directly as the numeric order is the same as the
6706 // lexicographic order. If one integer has fewer digits, it is scaled
6707 // by some power of 10 to have the same number of digits as the longer
6708 // integer. If the scaled integers are equal it means the shorter
6709 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006711 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6712 int x_log2 = IntegerLog2(x_scaled);
6713 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6714 x_log10 -= x_scaled < kPowersOf10[x_log10];
6715
6716 int y_log2 = IntegerLog2(y_scaled);
6717 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6718 y_log10 -= y_scaled < kPowersOf10[y_log10];
6719
6720 int tie = EQUAL;
6721
6722 if (x_log10 < y_log10) {
6723 // X has fewer digits. We would like to simply scale up X but that
6724 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6725 // be scaled up to 9_000_000_000. So we scale up by the next
6726 // smallest power and scale down Y to drop one digit. It is OK to
6727 // drop one digit from the longer integer since the final digit is
6728 // past the length of the shorter integer.
6729 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6730 y_scaled /= 10;
6731 tie = LESS;
6732 } else if (y_log10 < x_log10) {
6733 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6734 x_scaled /= 10;
6735 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006736 }
6737
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006738 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6739 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6740 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006741}
6742
6743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744static Object* StringInputBufferCompare(RuntimeState* state,
6745 String* x,
6746 String* y) {
6747 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6748 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006749 bufx.Reset(x);
6750 bufy.Reset(y);
6751 while (bufx.has_more() && bufy.has_more()) {
6752 int d = bufx.GetNext() - bufy.GetNext();
6753 if (d < 0) return Smi::FromInt(LESS);
6754 else if (d > 0) return Smi::FromInt(GREATER);
6755 }
6756
6757 // x is (non-trivial) prefix of y:
6758 if (bufy.has_more()) return Smi::FromInt(LESS);
6759 // y is prefix of x:
6760 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6761}
6762
6763
6764static Object* FlatStringCompare(String* x, String* y) {
6765 ASSERT(x->IsFlat());
6766 ASSERT(y->IsFlat());
6767 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6768 int prefix_length = x->length();
6769 if (y->length() < prefix_length) {
6770 prefix_length = y->length();
6771 equal_prefix_result = Smi::FromInt(GREATER);
6772 } else if (y->length() > prefix_length) {
6773 equal_prefix_result = Smi::FromInt(LESS);
6774 }
6775 int r;
6776 if (x->IsAsciiRepresentation()) {
6777 Vector<const char> x_chars = x->ToAsciiVector();
6778 if (y->IsAsciiRepresentation()) {
6779 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006780 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006781 } else {
6782 Vector<const uc16> y_chars = y->ToUC16Vector();
6783 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6784 }
6785 } else {
6786 Vector<const uc16> x_chars = x->ToUC16Vector();
6787 if (y->IsAsciiRepresentation()) {
6788 Vector<const char> y_chars = y->ToAsciiVector();
6789 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6790 } else {
6791 Vector<const uc16> y_chars = y->ToUC16Vector();
6792 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6793 }
6794 }
6795 Object* result;
6796 if (r == 0) {
6797 result = equal_prefix_result;
6798 } else {
6799 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6800 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 ASSERT(result ==
6802 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006803 return result;
6804}
6805
6806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006807RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808 NoHandleAllocation ha;
6809 ASSERT(args.length() == 2);
6810
6811 CONVERT_CHECKED(String, x, args[0]);
6812 CONVERT_CHECKED(String, y, args[1]);
6813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 // A few fast case tests before we flatten.
6817 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006818 if (y->length() == 0) {
6819 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006821 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 return Smi::FromInt(LESS);
6823 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006824
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006825 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006826 if (d < 0) return Smi::FromInt(LESS);
6827 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828
lrn@chromium.org303ada72010-10-27 09:33:13 +00006829 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006830 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006831 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6832 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006834 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006837 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839}
6840
6841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006842RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843 NoHandleAllocation ha;
6844 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006847 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006848 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849}
6850
6851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006852RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853 NoHandleAllocation ha;
6854 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006855 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006857 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006858 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006859}
6860
6861
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006862RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863 NoHandleAllocation ha;
6864 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006865 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006867 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006868 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869}
6870
6871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872static const double kPiDividedBy4 = 0.78539816339744830962;
6873
6874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006875RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876 NoHandleAllocation ha;
6877 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006878 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006880 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6881 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006882 double result;
6883 if (isinf(x) && isinf(y)) {
6884 // Make sure that the result in case of two infinite arguments
6885 // is a multiple of Pi / 4. The sign of the result is determined
6886 // by the first argument (x) and the sign of the second argument
6887 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888 int multiplier = (x < 0) ? -1 : 1;
6889 if (y < 0) multiplier *= 3;
6890 result = multiplier * kPiDividedBy4;
6891 } else {
6892 result = atan2(x, y);
6893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006894 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895}
6896
6897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006898RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899 NoHandleAllocation ha;
6900 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006901 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006902
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006903 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006904 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006905}
6906
6907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006908RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909 NoHandleAllocation ha;
6910 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006911 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006913 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915}
6916
6917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006921 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006922
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006923 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006924 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925}
6926
6927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006928RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929 NoHandleAllocation ha;
6930 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006931 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006933 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935}
6936
6937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006938RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 NoHandleAllocation ha;
6940 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006941 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006943 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006944 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945}
6946
6947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006948RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
6950 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006951 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006953 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006954
6955 // If the second argument is a smi, it is much faster to call the
6956 // custom powi() function than the generic pow().
6957 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006958 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006959 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006960 }
6961
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006962 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006963 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964}
6965
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006966// Fast version of Math.pow if we know that y is not an integer and
6967// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006968RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006969 NoHandleAllocation ha;
6970 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006971 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6972 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006973 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006974 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006975 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006976 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006977 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006979 }
6980}
6981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006983RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984 NoHandleAllocation ha;
6985 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006986 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006988 if (!args[0]->IsHeapNumber()) {
6989 // Must be smi. Return the argument unchanged for all the other types
6990 // to make fuzz-natives test happy.
6991 return args[0];
6992 }
6993
6994 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6995
6996 double value = number->value();
6997 int exponent = number->get_exponent();
6998 int sign = number->get_sign();
6999
danno@chromium.org160a7b02011-04-18 15:51:38 +00007000 if (exponent < -1) {
7001 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7002 if (sign) return isolate->heap()->minus_zero_value();
7003 return Smi::FromInt(0);
7004 }
7005
7006 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7007 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7008 // agument holds for 32-bit smis).
7009 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007010 return Smi::FromInt(static_cast<int>(value + 0.5));
7011 }
7012
7013 // If the magnitude is big enough, there's no place for fraction part. If we
7014 // try to add 0.5 to this number, 1.0 will be added instead.
7015 if (exponent >= 52) {
7016 return number;
7017 }
7018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007020
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007021 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007026RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 NoHandleAllocation ha;
7028 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007029 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007031 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033}
7034
7035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007036RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 NoHandleAllocation ha;
7038 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007039 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007041 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007051 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007056static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007057 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7058 181, 212, 243, 273, 304, 334};
7059 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7060 182, 213, 244, 274, 305, 335};
7061
7062 year += month / 12;
7063 month %= 12;
7064 if (month < 0) {
7065 year--;
7066 month += 12;
7067 }
7068
7069 ASSERT(month >= 0);
7070 ASSERT(month < 12);
7071
7072 // year_delta is an arbitrary number such that:
7073 // a) year_delta = -1 (mod 400)
7074 // b) year + year_delta > 0 for years in the range defined by
7075 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7076 // Jan 1 1970. This is required so that we don't run into integer
7077 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007078 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007079 // operations.
7080 static const int year_delta = 399999;
7081 static const int base_day = 365 * (1970 + year_delta) +
7082 (1970 + year_delta) / 4 -
7083 (1970 + year_delta) / 100 +
7084 (1970 + year_delta) / 400;
7085
7086 int year1 = year + year_delta;
7087 int day_from_year = 365 * year1 +
7088 year1 / 4 -
7089 year1 / 100 +
7090 year1 / 400 -
7091 base_day;
7092
7093 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007094 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007095 }
7096
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007097 return day_from_year + day_from_month_leap[month] + day - 1;
7098}
7099
7100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007101RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007102 NoHandleAllocation ha;
7103 ASSERT(args.length() == 3);
7104
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007105 CONVERT_SMI_ARG_CHECKED(year, 0);
7106 CONVERT_SMI_ARG_CHECKED(month, 1);
7107 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007108
7109 return Smi::FromInt(MakeDay(year, month, date));
7110}
7111
7112
7113static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7114static const int kDaysIn4Years = 4 * 365 + 1;
7115static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7116static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7117static const int kDays1970to2000 = 30 * 365 + 7;
7118static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7119 kDays1970to2000;
7120static const int kYearsOffset = 400000;
7121
7122static const char kDayInYear[] = {
7123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7124 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7125 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7126 22, 23, 24, 25, 26, 27, 28,
7127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7128 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7130 22, 23, 24, 25, 26, 27, 28, 29, 30,
7131 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7132 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7133 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7134 22, 23, 24, 25, 26, 27, 28, 29, 30,
7135 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7136 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7138 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7139 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7140 22, 23, 24, 25, 26, 27, 28, 29, 30,
7141 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7142 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7143 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7144 22, 23, 24, 25, 26, 27, 28, 29, 30,
7145 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7146 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7147
7148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7149 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7150 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7151 22, 23, 24, 25, 26, 27, 28,
7152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7153 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7154 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7155 22, 23, 24, 25, 26, 27, 28, 29, 30,
7156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7157 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7158 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7159 22, 23, 24, 25, 26, 27, 28, 29, 30,
7160 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7161 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7163 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7165 22, 23, 24, 25, 26, 27, 28, 29, 30,
7166 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7167 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7168 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7169 22, 23, 24, 25, 26, 27, 28, 29, 30,
7170 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7171 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7172
7173 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7174 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7175 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7176 22, 23, 24, 25, 26, 27, 28, 29,
7177 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7178 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7179 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7180 22, 23, 24, 25, 26, 27, 28, 29, 30,
7181 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7182 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7183 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7184 22, 23, 24, 25, 26, 27, 28, 29, 30,
7185 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7186 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7187 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7188 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7189 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7190 22, 23, 24, 25, 26, 27, 28, 29, 30,
7191 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7192 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7193 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7194 22, 23, 24, 25, 26, 27, 28, 29, 30,
7195 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7196 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7197
7198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7199 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7201 22, 23, 24, 25, 26, 27, 28,
7202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7203 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7205 22, 23, 24, 25, 26, 27, 28, 29, 30,
7206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7207 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7209 22, 23, 24, 25, 26, 27, 28, 29, 30,
7210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7213 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7215 22, 23, 24, 25, 26, 27, 28, 29, 30,
7216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7217 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7219 22, 23, 24, 25, 26, 27, 28, 29, 30,
7220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7221 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7222
7223static const char kMonthInYear[] = {
7224 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,
7225 0, 0, 0, 0, 0, 0,
7226 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,
7227 1, 1, 1,
7228 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,
7229 2, 2, 2, 2, 2, 2,
7230 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,
7231 3, 3, 3, 3, 3,
7232 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,
7233 4, 4, 4, 4, 4, 4,
7234 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,
7235 5, 5, 5, 5, 5,
7236 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,
7237 6, 6, 6, 6, 6, 6,
7238 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,
7239 7, 7, 7, 7, 7, 7,
7240 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,
7241 8, 8, 8, 8, 8,
7242 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,
7243 9, 9, 9, 9, 9, 9,
7244 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7245 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7246 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7247 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7248
7249 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,
7250 0, 0, 0, 0, 0, 0,
7251 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,
7252 1, 1, 1,
7253 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,
7254 2, 2, 2, 2, 2, 2,
7255 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,
7256 3, 3, 3, 3, 3,
7257 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,
7258 4, 4, 4, 4, 4, 4,
7259 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,
7260 5, 5, 5, 5, 5,
7261 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,
7262 6, 6, 6, 6, 6, 6,
7263 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,
7264 7, 7, 7, 7, 7, 7,
7265 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,
7266 8, 8, 8, 8, 8,
7267 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,
7268 9, 9, 9, 9, 9, 9,
7269 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7270 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7271 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7272 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7273
7274 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,
7275 0, 0, 0, 0, 0, 0,
7276 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,
7277 1, 1, 1, 1,
7278 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,
7279 2, 2, 2, 2, 2, 2,
7280 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,
7281 3, 3, 3, 3, 3,
7282 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,
7283 4, 4, 4, 4, 4, 4,
7284 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,
7285 5, 5, 5, 5, 5,
7286 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,
7287 6, 6, 6, 6, 6, 6,
7288 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,
7289 7, 7, 7, 7, 7, 7,
7290 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,
7291 8, 8, 8, 8, 8,
7292 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,
7293 9, 9, 9, 9, 9, 9,
7294 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7295 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7296 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7297 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7298
7299 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,
7300 0, 0, 0, 0, 0, 0,
7301 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,
7302 1, 1, 1,
7303 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,
7304 2, 2, 2, 2, 2, 2,
7305 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,
7306 3, 3, 3, 3, 3,
7307 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,
7308 4, 4, 4, 4, 4, 4,
7309 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,
7310 5, 5, 5, 5, 5,
7311 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,
7312 6, 6, 6, 6, 6, 6,
7313 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,
7314 7, 7, 7, 7, 7, 7,
7315 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,
7316 8, 8, 8, 8, 8,
7317 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,
7318 9, 9, 9, 9, 9, 9,
7319 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7320 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7321 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7322 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7323
7324
7325// This function works for dates from 1970 to 2099.
7326static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007327 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007328#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007329 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007330#endif
7331
7332 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7333 date %= kDaysIn4Years;
7334
7335 month = kMonthInYear[date];
7336 day = kDayInYear[date];
7337
7338 ASSERT(MakeDay(year, month, day) == save_date);
7339}
7340
7341
7342static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007343 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007344#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007345 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007346#endif
7347
7348 date += kDaysOffset;
7349 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7350 date %= kDaysIn400Years;
7351
7352 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7353
7354 date--;
7355 int yd1 = date / kDaysIn100Years;
7356 date %= kDaysIn100Years;
7357 year += 100 * yd1;
7358
7359 date++;
7360 int yd2 = date / kDaysIn4Years;
7361 date %= kDaysIn4Years;
7362 year += 4 * yd2;
7363
7364 date--;
7365 int yd3 = date / 365;
7366 date %= 365;
7367 year += yd3;
7368
7369 bool is_leap = (!yd1 || yd2) && !yd3;
7370
7371 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007372 ASSERT(is_leap || (date >= 0));
7373 ASSERT((date < 365) || (is_leap && (date < 366)));
7374 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7375 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7376 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007377
7378 if (is_leap) {
7379 day = kDayInYear[2*365 + 1 + date];
7380 month = kMonthInYear[2*365 + 1 + date];
7381 } else {
7382 day = kDayInYear[date];
7383 month = kMonthInYear[date];
7384 }
7385
7386 ASSERT(MakeDay(year, month, day) == save_date);
7387}
7388
7389
7390static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007391 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007392 if (date >= 0 && date < 32 * kDaysIn4Years) {
7393 DateYMDFromTimeAfter1970(date, year, month, day);
7394 } else {
7395 DateYMDFromTimeSlow(date, year, month, day);
7396 }
7397}
7398
7399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007400RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007401 NoHandleAllocation ha;
7402 ASSERT(args.length() == 2);
7403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007405 CONVERT_CHECKED(JSArray, res_array, args[1]);
7406
7407 int year, month, day;
7408 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 RUNTIME_ASSERT(res_array->elements()->map() ==
7411 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007412 FixedArray* elms = FixedArray::cast(res_array->elements());
7413 RUNTIME_ASSERT(elms->length() == 3);
7414
7415 elms->set(0, Smi::FromInt(year));
7416 elms->set(1, Smi::FromInt(month));
7417 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007424 HandleScope scope(isolate);
7425 ASSERT(args.length() == 3);
7426
7427 Handle<JSFunction> callee = args.at<JSFunction>(0);
7428 Object** parameters = reinterpret_cast<Object**>(args[1]);
7429 const int argument_count = Smi::cast(args[2])->value();
7430
7431 Handle<JSObject> result =
7432 isolate->factory()->NewArgumentsObject(callee, argument_count);
7433 // Allocate the elements if needed.
7434 int parameter_count = callee->shared()->formal_parameter_count();
7435 if (argument_count > 0) {
7436 if (parameter_count > 0) {
7437 int mapped_count = Min(argument_count, parameter_count);
7438 Handle<FixedArray> parameter_map =
7439 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7440 parameter_map->set_map(
7441 isolate->heap()->non_strict_arguments_elements_map());
7442
7443 Handle<Map> old_map(result->map());
7444 Handle<Map> new_map =
7445 isolate->factory()->CopyMapDropTransitions(old_map);
7446 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7447
7448 result->set_map(*new_map);
7449 result->set_elements(*parameter_map);
7450
7451 // Store the context and the arguments array at the beginning of the
7452 // parameter map.
7453 Handle<Context> context(isolate->context());
7454 Handle<FixedArray> arguments =
7455 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7456 parameter_map->set(0, *context);
7457 parameter_map->set(1, *arguments);
7458
7459 // Loop over the actual parameters backwards.
7460 int index = argument_count - 1;
7461 while (index >= mapped_count) {
7462 // These go directly in the arguments array and have no
7463 // corresponding slot in the parameter map.
7464 arguments->set(index, *(parameters - index - 1));
7465 --index;
7466 }
7467
7468 ScopeInfo<> scope_info(callee->shared()->scope_info());
7469 while (index >= 0) {
7470 // Detect duplicate names to the right in the parameter list.
7471 Handle<String> name = scope_info.parameter_name(index);
7472 int context_slot_count = scope_info.number_of_context_slots();
7473 bool duplicate = false;
7474 for (int j = index + 1; j < parameter_count; ++j) {
7475 if (scope_info.parameter_name(j).is_identical_to(name)) {
7476 duplicate = true;
7477 break;
7478 }
7479 }
7480
7481 if (duplicate) {
7482 // This goes directly in the arguments array with a hole in the
7483 // parameter map.
7484 arguments->set(index, *(parameters - index - 1));
7485 parameter_map->set_the_hole(index + 2);
7486 } else {
7487 // The context index goes in the parameter map with a hole in the
7488 // arguments array.
7489 int context_index = -1;
7490 for (int j = Context::MIN_CONTEXT_SLOTS;
7491 j < context_slot_count;
7492 ++j) {
7493 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7494 context_index = j;
7495 break;
7496 }
7497 }
7498 ASSERT(context_index >= 0);
7499 arguments->set_the_hole(index);
7500 parameter_map->set(index + 2, Smi::FromInt(context_index));
7501 }
7502
7503 --index;
7504 }
7505 } else {
7506 // If there is no aliasing, the arguments object elements are not
7507 // special in any way.
7508 Handle<FixedArray> elements =
7509 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7510 result->set_elements(*elements);
7511 for (int i = 0; i < argument_count; ++i) {
7512 elements->set(i, *(parameters - i - 1));
7513 }
7514 }
7515 }
7516 return *result;
7517}
7518
7519
7520RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007521 NoHandleAllocation ha;
7522 ASSERT(args.length() == 3);
7523
7524 JSFunction* callee = JSFunction::cast(args[0]);
7525 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007526 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007527
lrn@chromium.org303ada72010-10-27 09:33:13 +00007528 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 { MaybeObject* maybe_result =
7530 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007531 if (!maybe_result->ToObject(&result)) return maybe_result;
7532 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007533 // Allocate the elements if needed.
7534 if (length > 0) {
7535 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007536 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007538 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7539 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007540
7541 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007542 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007544 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007545
7546 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007547 for (int i = 0; i < length; i++) {
7548 array->set(i, *--parameters, mode);
7549 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007550 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007551 }
7552 return result;
7553}
7554
7555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007558 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007559 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007560 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007561 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562
whesse@chromium.org7b260152011-06-20 15:33:18 +00007563 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007564 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007565 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7568 context,
7569 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 return *result;
7571}
7572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007573
7574static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7575 int* total_argc) {
7576 // Find frame containing arguments passed to the caller.
7577 JavaScriptFrameIterator it;
7578 JavaScriptFrame* frame = it.frame();
7579 List<JSFunction*> functions(2);
7580 frame->GetFunctions(&functions);
7581 if (functions.length() > 1) {
7582 int inlined_frame_index = functions.length() - 1;
7583 JSFunction* inlined_function = functions[inlined_frame_index];
7584 int args_count = inlined_function->shared()->formal_parameter_count();
7585 ScopedVector<SlotRef> args_slots(args_count);
7586 SlotRef::ComputeSlotMappingForArguments(frame,
7587 inlined_frame_index,
7588 &args_slots);
7589
7590 *total_argc = bound_argc + args_count;
7591 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7592 for (int i = 0; i < args_count; i++) {
7593 Handle<Object> val = args_slots[i].GetValue();
7594 param_data[bound_argc + i] = val.location();
7595 }
7596 return param_data;
7597 } else {
7598 it.AdvanceToArgumentsFrame();
7599 frame = it.frame();
7600 int args_count = frame->ComputeParametersCount();
7601
7602 *total_argc = bound_argc + args_count;
7603 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7604 for (int i = 0; i < args_count; i++) {
7605 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7606 param_data[bound_argc + i] = val.location();
7607 }
7608 return param_data;
7609 }
7610}
7611
7612
7613RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007614 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007615 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007616 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007617 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007618
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007619 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007620 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007621 int bound_argc = 0;
7622 if (!args[1]->IsNull()) {
7623 CONVERT_ARG_CHECKED(JSArray, params, 1);
7624 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007625 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007626 bound_argc = Smi::cast(params->length())->value();
7627 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007628
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007629 int total_argc = 0;
7630 SmartPointer<Object**> param_data =
7631 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007632 for (int i = 0; i < bound_argc; i++) {
7633 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007634 param_data[i] = val.location();
7635 }
7636
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007637 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007638 Handle<Object> result =
7639 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007640 if (exception) {
7641 return Failure::Exception();
7642 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007643
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007644 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007645 return *result;
7646}
7647
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007649static void TrySettingInlineConstructStub(Isolate* isolate,
7650 Handle<JSFunction> function) {
7651 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007652 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007653 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007654 }
7655 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007656 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007657 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007658 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007659 function->shared()->set_construct_stub(
7660 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007661 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007662 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007663}
7664
7665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007666RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668 ASSERT(args.length() == 1);
7669
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007670 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007672 // If the constructor isn't a proper function we throw a type error.
7673 if (!constructor->IsJSFunction()) {
7674 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7675 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007676 isolate->factory()->NewTypeError("not_constructor", arguments);
7677 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007678 }
7679
7680 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007681
7682 // If function should not have prototype, construction is not allowed. In this
7683 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007684 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007685 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7686 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 isolate->factory()->NewTypeError("not_constructor", arguments);
7688 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007689 }
7690
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007691#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007692 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007693 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 if (debug->StepInActive()) {
7695 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007696 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007697#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007698
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007699 if (function->has_initial_map()) {
7700 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007701 // The 'Function' function ignores the receiver object when
7702 // called using 'new' and creates a new JSFunction object that
7703 // is returned. The receiver object is only used for error
7704 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007706 // allocate JSFunctions since it does not properly initialize
7707 // the shared part of the function. Since the receiver is
7708 // ignored anyway, we use the global object as the receiver
7709 // instead of a new JSFunction object. This way, errors are
7710 // reported the same way whether or not 'Function' is called
7711 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007712 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714 }
7715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007716 // The function should be compiled for the optimization hints to be
7717 // available. We cannot use EnsureCompiled because that forces a
7718 // compilation through the shared function info which makes it
7719 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007720 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007721 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007722
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007723 if (!function->has_initial_map() &&
7724 shared->IsInobjectSlackTrackingInProgress()) {
7725 // The tracking is already in progress for another function. We can only
7726 // track one initial_map at a time, so we force the completion before the
7727 // function is called as a constructor for the first time.
7728 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007729 }
7730
7731 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7733 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007734 // Delay setting the stub if inobject slack tracking is in progress.
7735 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007736 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007737 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 isolate->counters()->constructed_objects()->Increment();
7740 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007741
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007742 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007743}
7744
7745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007746RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007748 ASSERT(args.length() == 1);
7749
7750 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7751 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007753
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007755}
7756
7757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007758RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760 ASSERT(args.length() == 1);
7761
7762 Handle<JSFunction> function = args.at<JSFunction>(0);
7763#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007764 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007765 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007766 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 PrintF("]\n");
7768 }
7769#endif
7770
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007771 // Compile the target function. Here we compile using CompileLazyInLoop in
7772 // order to get the optimized version. This helps code like delta-blue
7773 // that calls performance-critical routines through constructors. A
7774 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7775 // direct call. Since the in-loop tracking takes place through CallICs
7776 // this means that things called through constructors are never known to
7777 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007779 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780 return Failure::Exception();
7781 }
7782
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007783 // All done. Return the compiled code.
7784 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007785 return function->code();
7786}
7787
7788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007789RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007790 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007791 ASSERT(args.length() == 1);
7792 Handle<JSFunction> function = args.at<JSFunction>(0);
7793 // If the function is not optimizable or debugger is active continue using the
7794 // code from the full compiler.
7795 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007796 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007797 if (FLAG_trace_opt) {
7798 PrintF("[failed to optimize ");
7799 function->PrintName();
7800 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7801 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007802 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007803 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007804 function->ReplaceCode(function->shared()->code());
7805 return function->code();
7806 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007807 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007808 return function->code();
7809 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007810 if (FLAG_trace_opt) {
7811 PrintF("[failed to optimize ");
7812 function->PrintName();
7813 PrintF(": optimized compilation failed]\n");
7814 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007815 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007816 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007817}
7818
7819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007820RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007821 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007822 ASSERT(args.length() == 1);
7823 RUNTIME_ASSERT(args[0]->IsSmi());
7824 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007825 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007826 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7827 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007828 int frames = deoptimizer->output_count();
7829
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007830 deoptimizer->MaterializeHeapNumbers();
7831 delete deoptimizer;
7832
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007833 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007834 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007835 for (int i = 0; i < frames - 1; i++) it.Advance();
7836 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007837
7838 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007839 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007840 Handle<Object> arguments;
7841 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007843 if (arguments.is_null()) {
7844 // FunctionGetArguments can't throw an exception, so cast away the
7845 // doubt with an assert.
7846 arguments = Handle<Object>(
7847 Accessors::FunctionGetArguments(*function,
7848 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007849 ASSERT(*arguments != isolate->heap()->null_value());
7850 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007851 }
7852 frame->SetExpression(i, *arguments);
7853 }
7854 }
7855
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007856 if (type == Deoptimizer::EAGER) {
7857 RUNTIME_ASSERT(function->IsOptimized());
7858 } else {
7859 RUNTIME_ASSERT(!function->IsOptimized());
7860 }
7861
7862 // Avoid doing too much work when running with --always-opt and keep
7863 // the optimized code around.
7864 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007865 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007866 }
7867
7868 // Count the number of optimized activations of the function.
7869 int activations = 0;
7870 while (!it.done()) {
7871 JavaScriptFrame* frame = it.frame();
7872 if (frame->is_optimized() && frame->function() == *function) {
7873 activations++;
7874 }
7875 it.Advance();
7876 }
7877
7878 // TODO(kasperl): For now, we cannot support removing the optimized
7879 // code when we have recursive invocations of the same function.
7880 if (activations == 0) {
7881 if (FLAG_trace_deopt) {
7882 PrintF("[removing optimized code for: ");
7883 function->PrintName();
7884 PrintF("]\n");
7885 }
7886 function->ReplaceCode(function->shared()->code());
7887 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007889}
7890
7891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007892RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007894 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007896}
7897
7898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007899RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007901 ASSERT(args.length() == 1);
7902 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007904
7905 Deoptimizer::DeoptimizeFunction(*function);
7906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007908}
7909
7910
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7912#if defined(USE_SIMULATOR)
7913 return isolate->heap()->true_value();
7914#else
7915 return isolate->heap()->false_value();
7916#endif
7917}
7918
7919
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007920RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7921 HandleScope scope(isolate);
7922 ASSERT(args.length() == 1);
7923 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7924 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7925 function->MarkForLazyRecompilation();
7926 return isolate->heap()->undefined_value();
7927}
7928
7929
lrn@chromium.org1c092762011-05-09 09:42:16 +00007930RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7931 HandleScope scope(isolate);
7932 ASSERT(args.length() == 1);
7933 if (!V8::UseCrankshaft()) {
7934 return Smi::FromInt(4); // 4 == "never".
7935 }
7936 if (FLAG_always_opt) {
7937 return Smi::FromInt(3); // 3 == "always".
7938 }
7939 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7940 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7941 : Smi::FromInt(2); // 2 == "no".
7942}
7943
7944
7945RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7946 HandleScope scope(isolate);
7947 ASSERT(args.length() == 1);
7948 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7949 return Smi::FromInt(function->shared()->opt_count());
7950}
7951
7952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007953RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007955 ASSERT(args.length() == 1);
7956 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7957
7958 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007959 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007960
7961 // We have hit a back edge in an unoptimized frame for a function that was
7962 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007963 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007964 // Keep track of whether we've succeeded in optimizing.
7965 bool succeeded = unoptimized->optimizable();
7966 if (succeeded) {
7967 // If we are trying to do OSR when there are already optimized
7968 // activations of the function, it means (a) the function is directly or
7969 // indirectly recursive and (b) an optimized invocation has been
7970 // deoptimized so that we are currently in an unoptimized activation.
7971 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007972 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973 while (succeeded && !it.done()) {
7974 JavaScriptFrame* frame = it.frame();
7975 succeeded = !frame->is_optimized() || frame->function() != *function;
7976 it.Advance();
7977 }
7978 }
7979
7980 int ast_id = AstNode::kNoNumber;
7981 if (succeeded) {
7982 // The top JS function is this one, the PC is somewhere in the
7983 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007984 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985 JavaScriptFrame* frame = it.frame();
7986 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007987 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007988 ASSERT(unoptimized->contains(frame->pc()));
7989
7990 // Use linear search of the unoptimized code's stack check table to find
7991 // the AST id matching the PC.
7992 Address start = unoptimized->instruction_start();
7993 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007994 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007995 uint32_t table_length = Memory::uint32_at(table_cursor);
7996 table_cursor += kIntSize;
7997 for (unsigned i = 0; i < table_length; ++i) {
7998 // Table entries are (AST id, pc offset) pairs.
7999 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8000 if (pc_offset == target_pc_offset) {
8001 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8002 break;
8003 }
8004 table_cursor += 2 * kIntSize;
8005 }
8006 ASSERT(ast_id != AstNode::kNoNumber);
8007 if (FLAG_trace_osr) {
8008 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8009 function->PrintName();
8010 PrintF("]\n");
8011 }
8012
8013 // Try to compile the optimized code. A true return value from
8014 // CompileOptimized means that compilation succeeded, not necessarily
8015 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008016 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8017 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008018 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8019 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008020 if (data->OsrPcOffset()->value() >= 0) {
8021 if (FLAG_trace_osr) {
8022 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008023 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008024 }
8025 ASSERT(data->OsrAstId()->value() == ast_id);
8026 } else {
8027 // We may never generate the desired OSR entry if we emit an
8028 // early deoptimize.
8029 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008030 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 } else {
8032 succeeded = false;
8033 }
8034 }
8035
8036 // Revert to the original stack checks in the original unoptimized code.
8037 if (FLAG_trace_osr) {
8038 PrintF("[restoring original stack checks in ");
8039 function->PrintName();
8040 PrintF("]\n");
8041 }
8042 StackCheckStub check_stub;
8043 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008044 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008045 Deoptimizer::RevertStackCheckCode(*unoptimized,
8046 *check_code,
8047 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008048
8049 // Allow OSR only at nesting level zero again.
8050 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8051
8052 // If the optimization attempt succeeded, return the AST id tagged as a
8053 // smi. This tells the builtin that we need to translate the unoptimized
8054 // frame to an optimized one.
8055 if (succeeded) {
8056 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8057 return Smi::FromInt(ast_id);
8058 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008059 if (function->IsMarkedForLazyRecompilation()) {
8060 function->ReplaceCode(function->shared()->code());
8061 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008062 return Smi::FromInt(-1);
8063 }
8064}
8065
8066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008069 ASSERT(args.length() == 1);
8070 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8071 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008077 ASSERT(args.length() == 1);
8078 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8079 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8080}
8081
8082
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008084 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008085 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008086
kasper.lund7276f142008-07-30 08:49:36 +00008087 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008088 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008089 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 { MaybeObject* maybe_result =
8091 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008092 if (!maybe_result->ToObject(&result)) return maybe_result;
8093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008095 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008096
kasper.lund7276f142008-07-30 08:49:36 +00008097 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008098}
8099
lrn@chromium.org303ada72010-10-27 09:33:13 +00008100
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008101RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8102 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008103 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008104 JSObject* extension_object;
8105 if (args[0]->IsJSObject()) {
8106 extension_object = JSObject::cast(args[0]);
8107 } else {
8108 // Convert the object to a proper JavaScript object.
8109 MaybeObject* maybe_js_object = args[0]->ToObject();
8110 if (!maybe_js_object->To(&extension_object)) {
8111 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8112 HandleScope scope(isolate);
8113 Handle<Object> handle = args.at<Object>(0);
8114 Handle<Object> result =
8115 isolate->factory()->NewTypeError("with_expression",
8116 HandleVector(&handle, 1));
8117 return isolate->Throw(*result);
8118 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008119 return maybe_js_object;
8120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121 }
8122 }
8123
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008124 JSFunction* function;
8125 if (args[1]->IsSmi()) {
8126 // A smi sentinel indicates a context nested inside global code rather
8127 // than some function. There is a canonical empty function that can be
8128 // gotten from the global context.
8129 function = isolate->context()->global_context()->closure();
8130 } else {
8131 function = JSFunction::cast(args[1]);
8132 }
8133
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008134 Context* context;
8135 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008136 isolate->heap()->AllocateWithContext(function,
8137 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008138 extension_object);
8139 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008140 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008141 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008142}
8143
8144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008145RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008146 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008147 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008148 String* name = String::cast(args[0]);
8149 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008150 JSFunction* function;
8151 if (args[2]->IsSmi()) {
8152 // A smi sentinel indicates a context nested inside global code rather
8153 // than some function. There is a canonical empty function that can be
8154 // gotten from the global context.
8155 function = isolate->context()->global_context()->closure();
8156 } else {
8157 function = JSFunction::cast(args[2]);
8158 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008159 Context* context;
8160 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008161 isolate->heap()->AllocateCatchContext(function,
8162 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008163 name,
8164 thrown_object);
8165 if (!maybe_context->To(&context)) return maybe_context;
8166 isolate->set_context(context);
8167 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008168}
8169
8170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008171RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173 ASSERT(args.length() == 2);
8174
8175 CONVERT_ARG_CHECKED(Context, context, 0);
8176 CONVERT_ARG_CHECKED(String, name, 1);
8177
8178 int index;
8179 PropertyAttributes attributes;
8180 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008181 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008182
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008183 // If the slot was not found the result is true.
8184 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008185 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 }
8187
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008188 // If the slot was found in a context, it should be DONT_DELETE.
8189 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008190 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008191 }
8192
8193 // The slot was found in a JSObject, either a context extension object,
8194 // the global object, or an arguments object. Try to delete it
8195 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8196 // which allows deleting all parameters in functions that mention
8197 // 'arguments', we do this even for the case of slots found on an
8198 // arguments object. The slot was found on an arguments object if the
8199 // index is non-negative.
8200 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8201 if (index >= 0) {
8202 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8203 } else {
8204 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8205 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206}
8207
8208
ager@chromium.orga1645e22009-09-09 19:27:10 +00008209// A mechanism to return a pair of Object pointers in registers (if possible).
8210// How this is achieved is calling convention-dependent.
8211// All currently supported x86 compiles uses calling conventions that are cdecl
8212// variants where a 64-bit value is returned in two 32-bit registers
8213// (edx:eax on ia32, r1:r0 on ARM).
8214// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8215// In Win64 calling convention, a struct of two pointers is returned in memory,
8216// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008217#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008218struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008219 MaybeObject* x;
8220 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008221};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008222
lrn@chromium.org303ada72010-10-27 09:33:13 +00008223static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008224 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008225 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8226 // In Win64 they are assigned to a hidden first argument.
8227 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008228}
8229#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008230typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008231static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008233 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008235#endif
8236
8237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238static inline MaybeObject* Unhole(Heap* heap,
8239 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008240 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8242 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244}
8245
8246
danno@chromium.org40cb8782011-05-25 07:58:50 +00008247static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8248 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008249 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008250 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008251 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008252 JSFunction* context_extension_function =
8253 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008254 // If the holder isn't a context extension object, we just return it
8255 // as the receiver. This allows arguments objects to be used as
8256 // receivers, but only if they are put in the context scope chain
8257 // explicitly via a with-statement.
8258 Object* constructor = holder->map()->constructor();
8259 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008260 // Fall back to using the global object as the implicit receiver if
8261 // the property turns out to be a local variable allocated in a
8262 // context extension object - introduced via eval. Implicit global
8263 // receivers are indicated with the hole value.
8264 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008265}
8266
8267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268static ObjectPair LoadContextSlotHelper(Arguments args,
8269 Isolate* isolate,
8270 bool throw_error) {
8271 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008272 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008274 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008276 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008278 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279
8280 int index;
8281 PropertyAttributes attributes;
8282 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008283 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008285 // If the index is non-negative, the slot has been found in a local
8286 // variable or a parameter. Read it from the context object or the
8287 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008289 // If the "property" we were looking for is a local variable or an
8290 // argument in a context, the receiver is the global object; see
8291 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008292 //
8293 // Use the hole as the receiver to signal that the receiver is
8294 // implicit and that the global receiver should be used.
8295 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008296 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008297 ? Context::cast(*holder)->get(index)
8298 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008299 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 }
8301
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008302 // If the holder is found, we read the property from it.
8303 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008304 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008305 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008306 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008307 if (object->IsGlobalObject()) {
8308 receiver = GlobalObject::cast(object)->global_receiver();
8309 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008310 // Use the hole as the receiver to signal that the receiver is
8311 // implicit and that the global receiver should be used.
8312 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008313 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008314 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008315 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008316
8317 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008318 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008319
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008320 // No need to unhole the value here. This is taken care of by the
8321 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008322 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008323 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 }
8325
8326 if (throw_error) {
8327 // The property doesn't exist - throw exception.
8328 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008329 isolate->factory()->NewReferenceError("not_defined",
8330 HandleVector(&name, 1));
8331 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008333 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 return MakePair(isolate->heap()->undefined_value(),
8335 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008336 }
8337}
8338
8339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008340RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008341 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342}
8343
8344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008345RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008347}
8348
8349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008350RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008352 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008356 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008357 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008358 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8359 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008360 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361
8362 int index;
8363 PropertyAttributes attributes;
8364 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008365 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366
8367 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008368 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 // Ignore if read_only variable.
8370 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008371 // Context is a fixed array and set cannot fail.
8372 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008373 } else if (strict_mode == kStrictMode) {
8374 // Setting read only property in strict mode.
8375 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 isolate->factory()->NewTypeError("strict_cannot_assign",
8377 HandleVector(&name, 1));
8378 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008379 }
8380 } else {
8381 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008382 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008383 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008384 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008385 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008386 return Failure::Exception();
8387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008388 }
8389 return *value;
8390 }
8391
8392 // Slow case: The property is not in a FixedArray context.
8393 // It is either in an JSObject extension context or it was not found.
8394 Handle<JSObject> context_ext;
8395
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008396 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008398 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008400 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008402
8403 if (strict_mode == kStrictMode) {
8404 // Throw in strict mode (assignment to undefined variable).
8405 Handle<Object> error =
8406 isolate->factory()->NewReferenceError(
8407 "not_defined", HandleVector(&name, 1));
8408 return isolate->Throw(*error);
8409 }
8410 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008411 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 }
8414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008415 // Set the property, but ignore if read_only variable on the context
8416 // extension object itself.
8417 if ((attributes & READ_ONLY) == 0 ||
8418 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008419 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008421 SetProperty(context_ext, name, value, NONE, strict_mode));
8422 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008423 // Setting read only property in strict mode.
8424 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 isolate->factory()->NewTypeError(
8426 "strict_cannot_assign", HandleVector(&name, 1));
8427 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008428 }
8429 return *value;
8430}
8431
8432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008433RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008434 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435 ASSERT(args.length() == 1);
8436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438}
8439
8440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008441RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008442 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443 ASSERT(args.length() == 1);
8444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446}
8447
8448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008449RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008450 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008451 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008452}
8453
8454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008455RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008456 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457 ASSERT(args.length() == 1);
8458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 isolate->factory()->NewReferenceError("not_defined",
8462 HandleVector(&name, 1));
8463 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464}
8465
8466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008467RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008468 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008469
8470 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 if (isolate->stack_guard()->IsStackOverflow()) {
8472 NoHandleAllocation na;
8473 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008474 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008475
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008476 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008477}
8478
8479
8480// NOTE: These PrintXXX functions are defined for all builds (not just
8481// DEBUG builds) because we may want to be able to trace function
8482// calls in all modes.
8483static void PrintString(String* str) {
8484 // not uncommon to have empty strings
8485 if (str->length() > 0) {
8486 SmartPointer<char> s =
8487 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8488 PrintF("%s", *s);
8489 }
8490}
8491
8492
8493static void PrintObject(Object* obj) {
8494 if (obj->IsSmi()) {
8495 PrintF("%d", Smi::cast(obj)->value());
8496 } else if (obj->IsString() || obj->IsSymbol()) {
8497 PrintString(String::cast(obj));
8498 } else if (obj->IsNumber()) {
8499 PrintF("%g", obj->Number());
8500 } else if (obj->IsFailure()) {
8501 PrintF("<failure>");
8502 } else if (obj->IsUndefined()) {
8503 PrintF("<undefined>");
8504 } else if (obj->IsNull()) {
8505 PrintF("<null>");
8506 } else if (obj->IsTrue()) {
8507 PrintF("<true>");
8508 } else if (obj->IsFalse()) {
8509 PrintF("<false>");
8510 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008511 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 }
8513}
8514
8515
8516static int StackSize() {
8517 int n = 0;
8518 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8519 return n;
8520}
8521
8522
8523static void PrintTransition(Object* result) {
8524 // indentation
8525 { const int nmax = 80;
8526 int n = StackSize();
8527 if (n <= nmax)
8528 PrintF("%4d:%*s", n, n, "");
8529 else
8530 PrintF("%4d:%*s", n, nmax, "...");
8531 }
8532
8533 if (result == NULL) {
8534 // constructor calls
8535 JavaScriptFrameIterator it;
8536 JavaScriptFrame* frame = it.frame();
8537 if (frame->IsConstructor()) PrintF("new ");
8538 // function name
8539 Object* fun = frame->function();
8540 if (fun->IsJSFunction()) {
8541 PrintObject(JSFunction::cast(fun)->shared()->name());
8542 } else {
8543 PrintObject(fun);
8544 }
8545 // function arguments
8546 // (we are intentionally only printing the actually
8547 // supplied parameters, not all parameters required)
8548 PrintF("(this=");
8549 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008550 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 for (int i = 0; i < length; i++) {
8552 PrintF(", ");
8553 PrintObject(frame->GetParameter(i));
8554 }
8555 PrintF(") {\n");
8556
8557 } else {
8558 // function result
8559 PrintF("} -> ");
8560 PrintObject(result);
8561 PrintF("\n");
8562 }
8563}
8564
8565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008566RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008567 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568 NoHandleAllocation ha;
8569 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571}
8572
8573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008574RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008575 NoHandleAllocation ha;
8576 PrintTransition(args[0]);
8577 return args[0]; // return TOS
8578}
8579
8580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008582 NoHandleAllocation ha;
8583 ASSERT(args.length() == 1);
8584
8585#ifdef DEBUG
8586 if (args[0]->IsString()) {
8587 // If we have a string, assume it's a code "marker"
8588 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008589 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008591 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8592 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008593 } else {
8594 PrintF("DebugPrint: ");
8595 }
8596 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008597 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008598 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008599 HeapObject::cast(args[0])->map()->Print();
8600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008602 // ShortPrint is available in release mode. Print is not.
8603 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604#endif
8605 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008606 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607
8608 return args[0]; // return TOS
8609}
8610
8611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008612RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008613 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008614 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 isolate->PrintStack();
8616 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617}
8618
8619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008620RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008622 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623
8624 // According to ECMA-262, section 15.9.1, page 117, the precision of
8625 // the number in a Date object representing a particular instant in
8626 // time is milliseconds. Therefore, we floor the result of getting
8627 // the OS time.
8628 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008629 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630}
8631
8632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008633RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008635 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008637 CONVERT_ARG_CHECKED(String, str, 0);
8638 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008640 CONVERT_ARG_CHECKED(JSArray, output, 1);
8641 RUNTIME_ASSERT(output->HasFastElements());
8642
8643 AssertNoAllocation no_allocation;
8644
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008645 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008646 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8647 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008648 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008649 result = DateParser::Parse(str->ToAsciiVector(),
8650 output_array,
8651 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008653 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008654 result = DateParser::Parse(str->ToUC16Vector(),
8655 output_array,
8656 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008657 }
8658
8659 if (result) {
8660 return *output;
8661 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008662 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 }
8664}
8665
8666
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008667RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 NoHandleAllocation ha;
8669 ASSERT(args.length() == 1);
8670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008671 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008672 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674}
8675
8676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008677RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008679 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682}
8683
8684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008685RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686 NoHandleAllocation ha;
8687 ASSERT(args.length() == 1);
8688
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008689 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008690 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691}
8692
8693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008694RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008695 ASSERT(args.length() == 1);
8696 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008698 return JSGlobalObject::cast(global)->global_receiver();
8699}
8700
8701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008702RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008704 ASSERT_EQ(1, args.length());
8705 CONVERT_ARG_CHECKED(String, source, 0);
8706
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008707 source = Handle<String>(source->TryFlattenGetString());
8708 // Optimized fast case where we only have ascii characters.
8709 Handle<Object> result;
8710 if (source->IsSeqAsciiString()) {
8711 result = JsonParser<true>::Parse(source);
8712 } else {
8713 result = JsonParser<false>::Parse(source);
8714 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008715 if (result.is_null()) {
8716 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008717 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008718 return Failure::Exception();
8719 }
8720 return *result;
8721}
8722
8723
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008724bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8725 Handle<Context> context) {
8726 if (context->allow_code_gen_from_strings()->IsFalse()) {
8727 // Check with callback if set.
8728 AllowCodeGenerationFromStringsCallback callback =
8729 isolate->allow_code_gen_callback();
8730 if (callback == NULL) {
8731 // No callback set and code generation disallowed.
8732 return false;
8733 } else {
8734 // Callback set. Let it decide if code generation is allowed.
8735 VMState state(isolate, EXTERNAL);
8736 return callback(v8::Utils::ToLocal(context));
8737 }
8738 }
8739 return true;
8740}
8741
8742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008743RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008744 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008745 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008746 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008747
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008748 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008749 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008750
8751 // Check if global context allows code generation from
8752 // strings. Throw an exception if it doesn't.
8753 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8754 return isolate->Throw(*isolate->factory()->NewError(
8755 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8756 }
8757
8758 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008759 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8760 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008761 true,
8762 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008763 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008765 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8766 context,
8767 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008768 return *fun;
8769}
8770
8771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008772static ObjectPair CompileGlobalEval(Isolate* isolate,
8773 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008774 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008775 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008776 Handle<Context> context = Handle<Context>(isolate->context());
8777 Handle<Context> global_context = Handle<Context>(context->global_context());
8778
8779 // Check if global context allows code generation from
8780 // strings. Throw an exception if it doesn't.
8781 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8782 isolate->Throw(*isolate->factory()->NewError(
8783 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8784 return MakePair(Failure::Exception(), NULL);
8785 }
8786
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008787 // Deal with a normal eval call with a string argument. Compile it
8788 // and return the compiled function bound in the local context.
8789 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8790 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008792 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008793 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008794 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 Handle<JSFunction> compiled =
8796 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008797 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008798 return MakePair(*compiled, *receiver);
8799}
8800
8801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008802RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008803 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008805 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008806 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008807 Handle<Object> receiver; // Will be overwritten.
8808
8809 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008810 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008811#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008813 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008814 StackFrameLocator locator;
8815 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008816 ASSERT(Context::cast(frame->context()) == *context);
8817#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008818
8819 // Find where the 'eval' symbol is bound. It is unaliased only if
8820 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008821 int index = -1;
8822 PropertyAttributes attributes = ABSENT;
8823 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8825 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008826 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008827 // Stop search when eval is found or when the global context is
8828 // reached.
8829 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008830 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008831 }
8832
iposva@chromium.org245aa852009-02-10 00:49:54 +00008833 // If eval could not be resolved, it has been deleted and we need to
8834 // throw a reference error.
8835 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008836 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008837 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008838 isolate->factory()->NewReferenceError("not_defined",
8839 HandleVector(&name, 1));
8840 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008841 }
8842
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008843 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008844 // 'eval' is not bound in the global context. Just call the function
8845 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008846 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008847 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008848 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008849 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008850 }
8851
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008852 // 'eval' is bound in the global context, but it may have been overwritten.
8853 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008854 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008855 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008856 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008857 }
8858
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008859 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008860 return CompileGlobalEval(isolate,
8861 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008862 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008863 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008864}
8865
8866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008867RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008868 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008870 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008871 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008872
8873 // 'eval' is bound in the global context, but it may have been overwritten.
8874 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008876 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008877 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008878 }
8879
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008880 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 return CompileGlobalEval(isolate,
8882 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008883 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008884 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008885}
8886
8887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008888RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889 // This utility adjusts the property attributes for newly created Function
8890 // object ("new Function(...)") by changing the map.
8891 // All it does is changing the prototype property to enumerable
8892 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 ASSERT(args.length() == 1);
8895 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008896
8897 Handle<Map> map = func->shared()->strict_mode()
8898 ? isolate->strict_mode_function_instance_map()
8899 : isolate->function_instance_map();
8900
8901 ASSERT(func->map()->instance_type() == map->instance_type());
8902 ASSERT(func->map()->instance_size() == map->instance_size());
8903 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904 return *func;
8905}
8906
8907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008908RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008909 // Allocate a block of memory in NewSpace (filled with a filler).
8910 // Use as fallback for allocation in generated code when NewSpace
8911 // is full.
8912 ASSERT(args.length() == 1);
8913 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8914 int size = size_smi->value();
8915 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8916 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 Heap* heap = isolate->heap();
8918 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008919 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008920 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008922 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008923 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008924 }
8925 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008926 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008927}
8928
8929
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008930// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008931// array. Returns true if the element was pushed on the stack and
8932// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008933RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008934 ASSERT(args.length() == 2);
8935 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008936 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008937 RUNTIME_ASSERT(array->HasFastElements());
8938 int length = Smi::cast(array->length())->value();
8939 FixedArray* elements = FixedArray::cast(array->elements());
8940 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008942 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008943 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008944 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008945 { MaybeObject* maybe_obj =
8946 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008947 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8948 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008950}
8951
8952
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008953/**
8954 * A simple visitor visits every element of Array's.
8955 * The backend storage can be a fixed array for fast elements case,
8956 * or a dictionary for sparse array. Since Dictionary is a subtype
8957 * of FixedArray, the class can be used by both fast and slow cases.
8958 * The second parameter of the constructor, fast_elements, specifies
8959 * whether the storage is a FixedArray or Dictionary.
8960 *
8961 * An index limit is used to deal with the situation that a result array
8962 * length overflows 32-bit non-negative integer.
8963 */
8964class ArrayConcatVisitor {
8965 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008966 ArrayConcatVisitor(Isolate* isolate,
8967 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008968 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 isolate_(isolate),
8970 storage_(Handle<FixedArray>::cast(
8971 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008972 index_offset_(0u),
8973 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008974
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008975 ~ArrayConcatVisitor() {
8976 clear_storage();
8977 }
8978
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008979 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008981 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008982
8983 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008984 if (index < static_cast<uint32_t>(storage_->length())) {
8985 storage_->set(index, *elm);
8986 return;
8987 }
8988 // Our initial estimate of length was foiled, possibly by
8989 // getters on the arrays increasing the length of later arrays
8990 // during iteration.
8991 // This shouldn't happen in anything but pathological cases.
8992 SetDictionaryMode(index);
8993 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008994 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008995 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008996 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008999 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009000 // Dictionary needed to grow.
9001 clear_storage();
9002 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009003 }
9004}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009005
9006 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009007 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9008 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009009 } else {
9010 index_offset_ += delta;
9011 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009012 }
9013
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009014 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009016 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009017 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009018 Handle<Map> map;
9019 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009020 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009022 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009023 }
9024 array->set_map(*map);
9025 array->set_length(*length);
9026 array->set_elements(*storage_);
9027 return array;
9028 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009029
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009030 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009031 // Convert storage to dictionary mode.
9032 void SetDictionaryMode(uint32_t index) {
9033 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009034 Handle<FixedArray> current_storage(*storage_);
9035 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009036 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009037 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9038 for (uint32_t i = 0; i < current_length; i++) {
9039 HandleScope loop_scope;
9040 Handle<Object> element(current_storage->get(i));
9041 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009042 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009044 if (!new_storage.is_identical_to(slow_storage)) {
9045 slow_storage = loop_scope.CloseAndEscape(new_storage);
9046 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009047 }
9048 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009049 clear_storage();
9050 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009051 fast_elements_ = false;
9052 }
9053
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009054 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055 isolate_->global_handles()->Destroy(
9056 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009057 }
9058
9059 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 storage_ = Handle<FixedArray>::cast(
9061 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009062 }
9063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009065 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009066 // Index after last seen index. Always less than or equal to
9067 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009068 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009069 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009070};
9071
9072
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009073static uint32_t EstimateElementCount(Handle<JSArray> array) {
9074 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9075 int element_count = 0;
9076 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009077 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009078 // Fast elements can't have lengths that are not representable by
9079 // a 32-bit signed integer.
9080 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9081 int fast_length = static_cast<int>(length);
9082 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9083 for (int i = 0; i < fast_length; i++) {
9084 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009085 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009086 break;
9087 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009088 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009089 Handle<NumberDictionary> dictionary(
9090 NumberDictionary::cast(array->elements()));
9091 int capacity = dictionary->Capacity();
9092 for (int i = 0; i < capacity; i++) {
9093 Handle<Object> key(dictionary->KeyAt(i));
9094 if (dictionary->IsKey(*key)) {
9095 element_count++;
9096 }
9097 }
9098 break;
9099 }
9100 default:
9101 // External arrays are always dense.
9102 return length;
9103 }
9104 // As an estimate, we assume that the prototype doesn't contain any
9105 // inherited elements.
9106 return element_count;
9107}
9108
9109
9110
9111template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112static void IterateExternalArrayElements(Isolate* isolate,
9113 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009114 bool elements_are_ints,
9115 bool elements_are_guaranteed_smis,
9116 ArrayConcatVisitor* visitor) {
9117 Handle<ExternalArrayClass> array(
9118 ExternalArrayClass::cast(receiver->elements()));
9119 uint32_t len = static_cast<uint32_t>(array->length());
9120
9121 ASSERT(visitor != NULL);
9122 if (elements_are_ints) {
9123 if (elements_are_guaranteed_smis) {
9124 for (uint32_t j = 0; j < len; j++) {
9125 HandleScope loop_scope;
9126 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9127 visitor->visit(j, e);
9128 }
9129 } else {
9130 for (uint32_t j = 0; j < len; j++) {
9131 HandleScope loop_scope;
9132 int64_t val = static_cast<int64_t>(array->get(j));
9133 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9134 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9135 visitor->visit(j, e);
9136 } else {
9137 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009139 visitor->visit(j, e);
9140 }
9141 }
9142 }
9143 } else {
9144 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009145 HandleScope loop_scope(isolate);
9146 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009147 visitor->visit(j, e);
9148 }
9149 }
9150}
9151
9152
9153// Used for sorting indices in a List<uint32_t>.
9154static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9155 uint32_t a = *ap;
9156 uint32_t b = *bp;
9157 return (a == b) ? 0 : (a < b) ? -1 : 1;
9158}
9159
9160
9161static void CollectElementIndices(Handle<JSObject> object,
9162 uint32_t range,
9163 List<uint32_t>* indices) {
9164 JSObject::ElementsKind kind = object->GetElementsKind();
9165 switch (kind) {
9166 case JSObject::FAST_ELEMENTS: {
9167 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9168 uint32_t length = static_cast<uint32_t>(elements->length());
9169 if (range < length) length = range;
9170 for (uint32_t i = 0; i < length; i++) {
9171 if (!elements->get(i)->IsTheHole()) {
9172 indices->Add(i);
9173 }
9174 }
9175 break;
9176 }
9177 case JSObject::DICTIONARY_ELEMENTS: {
9178 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009179 uint32_t capacity = dict->Capacity();
9180 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009181 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009182 Handle<Object> k(dict->KeyAt(j));
9183 if (dict->IsKey(*k)) {
9184 ASSERT(k->IsNumber());
9185 uint32_t index = static_cast<uint32_t>(k->Number());
9186 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009187 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009188 }
9189 }
9190 }
9191 break;
9192 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 default: {
9194 int dense_elements_length;
9195 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009196 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009197 dense_elements_length =
9198 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009199 break;
9200 }
9201 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009202 dense_elements_length =
9203 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009204 break;
9205 }
9206 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009207 dense_elements_length =
9208 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009209 break;
9210 }
9211 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009212 dense_elements_length =
9213 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009214 break;
9215 }
9216 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009217 dense_elements_length =
9218 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009219 break;
9220 }
9221 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009222 dense_elements_length =
9223 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009224 break;
9225 }
9226 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009227 dense_elements_length =
9228 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009229 break;
9230 }
9231 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009232 dense_elements_length =
9233 ExternalFloatArray::cast(object->elements())->length();
9234 break;
9235 }
9236 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9237 dense_elements_length =
9238 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009239 break;
9240 }
9241 default:
9242 UNREACHABLE();
9243 dense_elements_length = 0;
9244 break;
9245 }
9246 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9247 if (range <= length) {
9248 length = range;
9249 // We will add all indices, so we might as well clear it first
9250 // and avoid duplicates.
9251 indices->Clear();
9252 }
9253 for (uint32_t i = 0; i < length; i++) {
9254 indices->Add(i);
9255 }
9256 if (length == range) return; // All indices accounted for already.
9257 break;
9258 }
9259 }
9260
9261 Handle<Object> prototype(object->GetPrototype());
9262 if (prototype->IsJSObject()) {
9263 // The prototype will usually have no inherited element indices,
9264 // but we have to check.
9265 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9266 }
9267}
9268
9269
9270/**
9271 * A helper function that visits elements of a JSArray in numerical
9272 * order.
9273 *
9274 * The visitor argument called for each existing element in the array
9275 * with the element index and the element's value.
9276 * Afterwards it increments the base-index of the visitor by the array
9277 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009278 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280static bool IterateElements(Isolate* isolate,
9281 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009282 ArrayConcatVisitor* visitor) {
9283 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9284 switch (receiver->GetElementsKind()) {
9285 case JSObject::FAST_ELEMENTS: {
9286 // Run through the elements FixedArray and use HasElement and GetElement
9287 // to check the prototype for missing elements.
9288 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9289 int fast_length = static_cast<int>(length);
9290 ASSERT(fast_length <= elements->length());
9291 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009292 HandleScope loop_scope(isolate);
9293 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009294 if (!element_value->IsTheHole()) {
9295 visitor->visit(j, element_value);
9296 } else if (receiver->HasElement(j)) {
9297 // Call GetElement on receiver, not its prototype, or getters won't
9298 // have the correct receiver.
9299 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009300 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 visitor->visit(j, element_value);
9302 }
9303 }
9304 break;
9305 }
9306 case JSObject::DICTIONARY_ELEMENTS: {
9307 Handle<NumberDictionary> dict(receiver->element_dictionary());
9308 List<uint32_t> indices(dict->Capacity() / 2);
9309 // Collect all indices in the object and the prototypes less
9310 // than length. This might introduce duplicates in the indices list.
9311 CollectElementIndices(receiver, length, &indices);
9312 indices.Sort(&compareUInt32);
9313 int j = 0;
9314 int n = indices.length();
9315 while (j < n) {
9316 HandleScope loop_scope;
9317 uint32_t index = indices[j];
9318 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009319 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009320 visitor->visit(index, element);
9321 // Skip to next different index (i.e., omit duplicates).
9322 do {
9323 j++;
9324 } while (j < n && indices[j] == index);
9325 }
9326 break;
9327 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009328 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9329 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9330 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009331 for (uint32_t j = 0; j < length; j++) {
9332 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9333 visitor->visit(j, e);
9334 }
9335 break;
9336 }
9337 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9338 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009339 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009340 break;
9341 }
9342 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9343 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 break;
9346 }
9347 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9348 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 break;
9351 }
9352 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9353 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355 break;
9356 }
9357 case JSObject::EXTERNAL_INT_ELEMENTS: {
9358 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 break;
9361 }
9362 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9363 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 break;
9366 }
9367 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9368 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009370 break;
9371 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009372 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9373 IterateExternalArrayElements<ExternalDoubleArray, double>(
9374 isolate, receiver, false, false, visitor);
9375 break;
9376 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009377 default:
9378 UNREACHABLE();
9379 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009380 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009381 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009382 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009383}
9384
9385
9386/**
9387 * Array::concat implementation.
9388 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009390 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009391 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009392RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009393 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009395
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9397 int argument_count = static_cast<int>(arguments->length()->Number());
9398 RUNTIME_ASSERT(arguments->HasFastElements());
9399 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009400
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 // Pass 1: estimate the length and number of elements of the result.
9402 // The actual length can be larger if any of the arguments have getters
9403 // that mutate other arguments (but will otherwise be precise).
9404 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009405
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009406 uint32_t estimate_result_length = 0;
9407 uint32_t estimate_nof_elements = 0;
9408 {
9409 for (int i = 0; i < argument_count; i++) {
9410 HandleScope loop_scope;
9411 Handle<Object> obj(elements->get(i));
9412 uint32_t length_estimate;
9413 uint32_t element_estimate;
9414 if (obj->IsJSArray()) {
9415 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9416 length_estimate =
9417 static_cast<uint32_t>(array->length()->Number());
9418 element_estimate =
9419 EstimateElementCount(array);
9420 } else {
9421 length_estimate = 1;
9422 element_estimate = 1;
9423 }
9424 // Avoid overflows by capping at kMaxElementCount.
9425 if (JSObject::kMaxElementCount - estimate_result_length <
9426 length_estimate) {
9427 estimate_result_length = JSObject::kMaxElementCount;
9428 } else {
9429 estimate_result_length += length_estimate;
9430 }
9431 if (JSObject::kMaxElementCount - estimate_nof_elements <
9432 element_estimate) {
9433 estimate_nof_elements = JSObject::kMaxElementCount;
9434 } else {
9435 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009436 }
9437 }
9438 }
9439
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009440 // If estimated number of elements is more than half of length, a
9441 // fixed array (fast case) is more time and space-efficient than a
9442 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009443 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009444
9445 Handle<FixedArray> storage;
9446 if (fast_case) {
9447 // The backing storage array must have non-existing elements to
9448 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009449 storage = isolate->factory()->NewFixedArrayWithHoles(
9450 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009451 } else {
9452 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9453 uint32_t at_least_space_for = estimate_nof_elements +
9454 (estimate_nof_elements >> 2);
9455 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009457 }
9458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009460
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 for (int i = 0; i < argument_count; i++) {
9462 Handle<Object> obj(elements->get(i));
9463 if (obj->IsJSArray()) {
9464 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009466 return Failure::Exception();
9467 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009468 } else {
9469 visitor.visit(0, obj);
9470 visitor.increase_index_offset(1);
9471 }
9472 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009473
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009475}
9476
9477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009478// This will not allocate (flatten the string), but it may run
9479// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009480RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009481 NoHandleAllocation ha;
9482 ASSERT(args.length() == 1);
9483
9484 CONVERT_CHECKED(String, string, args[0]);
9485 StringInputBuffer buffer(string);
9486 while (buffer.has_more()) {
9487 uint16_t character = buffer.GetNext();
9488 PrintF("%c", character);
9489 }
9490 return string;
9491}
9492
ager@chromium.org5ec48922009-05-05 07:25:34 +00009493// Moves all own elements of an object, that are below a limit, to positions
9494// starting at zero. All undefined values are placed after non-undefined values,
9495// and are followed by non-existing element. Does not change the length
9496// property.
9497// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009498RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009499 ASSERT(args.length() == 2);
9500 CONVERT_CHECKED(JSObject, object, args[0]);
9501 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9502 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503}
9504
9505
9506// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009507RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009508 ASSERT(args.length() == 2);
9509 CONVERT_CHECKED(JSArray, from, args[0]);
9510 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009511 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009512 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9514 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009515 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009516 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009517 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009518 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009519 Object* new_map;
9520 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009521 to->set_map(Map::cast(new_map));
9522 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009524 Object* obj;
9525 { MaybeObject* maybe_obj = from->ResetElements();
9526 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9527 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009528 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529 return to;
9530}
9531
9532
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009533// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009534RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009536 CONVERT_CHECKED(JSObject, object, args[0]);
9537 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009538 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009539 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009540 } else if (object->IsJSArray()) {
9541 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009543 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009544 }
9545}
9546
9547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009548RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009550
9551 ASSERT_EQ(3, args.length());
9552
ager@chromium.orgac091b72010-05-05 07:34:42 +00009553 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009554 Handle<Object> key1 = args.at<Object>(1);
9555 Handle<Object> key2 = args.at<Object>(2);
9556
9557 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009558 if (!key1->ToArrayIndex(&index1)
9559 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009560 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009561 }
9562
ager@chromium.orgac091b72010-05-05 07:34:42 +00009563 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9564 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009566 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009567 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009568
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 RETURN_IF_EMPTY_HANDLE(isolate,
9570 SetElement(jsobject, index1, tmp2, kStrictMode));
9571 RETURN_IF_EMPTY_HANDLE(isolate,
9572 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009575}
9576
9577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009579// might have elements. Can either return keys (positive integers) or
9580// intervals (pair of a negative integer (-start-1) followed by a
9581// positive (length)) or undefined values.
9582// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009583RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009585 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009586 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009588 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009589 // Create an array and get all the keys into it, then remove all the
9590 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009591 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 int keys_length = keys->length();
9593 for (int i = 0; i < keys_length; i++) {
9594 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009595 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009596 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 // Zap invalid keys.
9598 keys->set_undefined(i);
9599 }
9600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009603 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009606 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009607 uint32_t actual_length =
9608 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009609 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009612 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 }
9615}
9616
9617
9618// DefineAccessor takes an optional final argument which is the
9619// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9620// to the way accessors are implemented, it is set for both the getter
9621// and setter on the first call to DefineAccessor and ignored on
9622// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009623RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9625 // Compute attributes.
9626 PropertyAttributes attributes = NONE;
9627 if (args.length() == 5) {
9628 CONVERT_CHECKED(Smi, attrs, args[4]);
9629 int value = attrs->value();
9630 // Only attribute bits should be set.
9631 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9632 attributes = static_cast<PropertyAttributes>(value);
9633 }
9634
9635 CONVERT_CHECKED(JSObject, obj, args[0]);
9636 CONVERT_CHECKED(String, name, args[1]);
9637 CONVERT_CHECKED(Smi, flag, args[2]);
9638 CONVERT_CHECKED(JSFunction, fun, args[3]);
9639 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9640}
9641
9642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009643RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644 ASSERT(args.length() == 3);
9645 CONVERT_CHECKED(JSObject, obj, args[0]);
9646 CONVERT_CHECKED(String, name, args[1]);
9647 CONVERT_CHECKED(Smi, flag, args[2]);
9648 return obj->LookupAccessor(name, flag->value() == 0);
9649}
9650
9651
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009652#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009653RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009654 ASSERT(args.length() == 0);
9655 return Execution::DebugBreakHelper();
9656}
9657
9658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659// Helper functions for wrapping and unwrapping stack frame ids.
9660static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009661 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009662 return Smi::FromInt(id >> 2);
9663}
9664
9665
9666static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9667 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9668}
9669
9670
9671// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009672// args[0]: debug event listener function to set or null or undefined for
9673// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009677 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9678 args[0]->IsUndefined() ||
9679 args[0]->IsNull());
9680 Handle<Object> callback = args.at<Object>(0);
9681 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009682 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685}
9686
9687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009688RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009689 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 isolate->stack_guard()->DebugBreak();
9691 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009692}
9693
9694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695static MaybeObject* DebugLookupResultValue(Heap* heap,
9696 Object* receiver,
9697 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009698 LookupResult* result,
9699 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009700 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009702 case NORMAL:
9703 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009704 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 }
9707 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009708 case FIELD:
9709 value =
9710 JSObject::cast(
9711 result->holder())->FastPropertyAt(result->GetFieldIndex());
9712 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009714 }
9715 return value;
9716 case CONSTANT_FUNCTION:
9717 return result->GetConstantFunction();
9718 case CALLBACKS: {
9719 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009720 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009721 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009722 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009723 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009724 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009725 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009726 maybe_value = heap->isolate()->pending_exception();
9727 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009728 if (caught_exception != NULL) {
9729 *caught_exception = true;
9730 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009731 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009732 }
9733 return value;
9734 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009736 }
9737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009738 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009739 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009740 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009741 case CONSTANT_TRANSITION:
9742 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009744 default:
9745 UNREACHABLE();
9746 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009747 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749}
9750
9751
ager@chromium.org32912102009-01-16 10:38:43 +00009752// Get debugger related details for an object property.
9753// args[0]: object holding property
9754// args[1]: name of the property
9755//
9756// The array returned contains the following information:
9757// 0: Property value
9758// 1: Property details
9759// 2: Property value is exception
9760// 3: Getter function if defined
9761// 4: Setter function if defined
9762// Items 2-4 are only filled if the property has either a getter or a setter
9763// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009764RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009766
9767 ASSERT(args.length() == 2);
9768
9769 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9770 CONVERT_ARG_CHECKED(String, name, 1);
9771
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009772 // Make sure to set the current context to the context before the debugger was
9773 // entered (if the debugger is entered). The reason for switching context here
9774 // is that for some property lookups (accessors and interceptors) callbacks
9775 // into the embedding application can occour, and the embedding application
9776 // could have the assumption that its own global context is the current
9777 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 SaveContext save(isolate);
9779 if (isolate->debug()->InDebugger()) {
9780 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009781 }
9782
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009783 // Skip the global proxy as it has no properties and always delegates to the
9784 // real global object.
9785 if (obj->IsJSGlobalProxy()) {
9786 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9787 }
9788
9789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 // Check if the name is trivially convertible to an index and get the element
9791 // if so.
9792 uint32_t index;
9793 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009795 Object* element_or_char;
9796 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9799 return maybe_element_or_char;
9800 }
9801 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009802 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009803 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 }
9806
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009807 // Find the number of objects making up this.
9808 int length = LocalPrototypeChainLength(*obj);
9809
9810 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009811 Handle<JSObject> jsproto = obj;
9812 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009813 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009814 jsproto->LocalLookup(*name, &result);
9815 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009816 // LookupResult is not GC safe as it holds raw object pointers.
9817 // GC can happen later in this code so put the required fields into
9818 // local variables using handles when required for later use.
9819 PropertyType result_type = result.type();
9820 Handle<Object> result_callback_obj;
9821 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9823 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009824 }
9825 Smi* property_details = result.GetPropertyDetails().AsSmi();
9826 // DebugLookupResultValue can cause GC so details from LookupResult needs
9827 // to be copied to handles before this.
9828 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009829 Object* raw_value;
9830 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 DebugLookupResultValue(isolate->heap(), *obj, *name,
9832 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009833 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9834 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009835 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009836
9837 // If the callback object is a fixed array then it contains JavaScript
9838 // getter and/or setter.
9839 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9840 result_callback_obj->IsFixedArray();
9841 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009843 details->set(0, *value);
9844 details->set(1, property_details);
9845 if (hasJavaScriptAccessors) {
9846 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009847 caught_exception ? isolate->heap()->true_value()
9848 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009849 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9850 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9851 }
9852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009854 }
9855 if (i < length - 1) {
9856 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9857 }
9858 }
9859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861}
9862
9863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009864RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866
9867 ASSERT(args.length() == 2);
9868
9869 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9870 CONVERT_ARG_CHECKED(String, name, 1);
9871
9872 LookupResult result;
9873 obj->Lookup(*name, &result);
9874 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009876 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009877 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009878}
9879
9880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881// Return the property type calculated from the property details.
9882// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009883RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 ASSERT(args.length() == 1);
9885 CONVERT_CHECKED(Smi, details, args[0]);
9886 PropertyType type = PropertyDetails(details).type();
9887 return Smi::FromInt(static_cast<int>(type));
9888}
9889
9890
9891// Return the property attribute calculated from the property details.
9892// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009893RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009894 ASSERT(args.length() == 1);
9895 CONVERT_CHECKED(Smi, details, args[0]);
9896 PropertyAttributes attributes = PropertyDetails(details).attributes();
9897 return Smi::FromInt(static_cast<int>(attributes));
9898}
9899
9900
9901// Return the property insertion index calculated from the property details.
9902// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009903RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904 ASSERT(args.length() == 1);
9905 CONVERT_CHECKED(Smi, details, args[0]);
9906 int index = PropertyDetails(details).index();
9907 return Smi::FromInt(index);
9908}
9909
9910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911// Return property value from named interceptor.
9912// args[0]: object
9913// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009914RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 ASSERT(args.length() == 2);
9917 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9918 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9919 CONVERT_ARG_CHECKED(String, name, 1);
9920
9921 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009922 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923}
9924
9925
9926// Return element value from indexed interceptor.
9927// args[0]: object
9928// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009929RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931 ASSERT(args.length() == 2);
9932 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9933 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9934 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009936 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009937}
9938
9939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009940RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 ASSERT(args.length() >= 1);
9942 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009943 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 if (isolate->debug()->break_id() == 0 ||
9945 break_id != isolate->debug()->break_id()) {
9946 return isolate->Throw(
9947 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948 }
9949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951}
9952
9953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009954RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956 ASSERT(args.length() == 1);
9957
9958 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009959 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009960 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9961 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009962 if (!maybe_result->ToObject(&result)) return maybe_result;
9963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009964
9965 // Count all frames which are relevant to debugging stack trace.
9966 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009968 if (id == StackFrame::NO_ID) {
9969 // If there is no JavaScript stack frame count is 0.
9970 return Smi::FromInt(0);
9971 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009972
9973 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
9974 n += it.frame()->GetInlineCount();
9975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 return Smi::FromInt(n);
9977}
9978
9979
9980static const int kFrameDetailsFrameIdIndex = 0;
9981static const int kFrameDetailsReceiverIndex = 1;
9982static const int kFrameDetailsFunctionIndex = 2;
9983static const int kFrameDetailsArgumentCountIndex = 3;
9984static const int kFrameDetailsLocalCountIndex = 4;
9985static const int kFrameDetailsSourcePositionIndex = 5;
9986static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009987static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009988static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009989static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990
9991// Return an array with frame details
9992// args[0]: number: break id
9993// args[1]: number: frame index
9994//
9995// The array returned contains the following information:
9996// 0: Frame id
9997// 1: Receiver
9998// 2: Function
9999// 3: Argument count
10000// 4: Local count
10001// 5: Source position
10002// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010003// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010004// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005// Arguments name, value
10006// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010007// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010008RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010 ASSERT(args.length() == 2);
10011
10012 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010013 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010014 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10015 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010016 if (!maybe_check->ToObject(&check)) return maybe_check;
10017 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020
10021 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010023 if (id == StackFrame::NO_ID) {
10024 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010026 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010027
10028 int deoptimized_frame_index = -1; // Frame index in optimized frame.
10029 DeoptimizedFrameInfo* deoptimized_frame = NULL;
10030
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010032 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010034 if (index < count + it.frame()->GetInlineCount()) break;
10035 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010036 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010039 if (it.frame()->is_optimized()) {
10040 deoptimized_frame_index =
10041 it.frame()->GetInlineCount() - (index - count) - 1;
10042 deoptimized_frame = Deoptimizer::DebuggerInspectableFrame(
10043 it.frame(),
10044 deoptimized_frame_index,
10045 isolate);
10046 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010048 // Traverse the saved contexts chain to find the active context for the
10049 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010050 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010051 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052 save = save->prev();
10053 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010054 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055
10056 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058
10059 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010060 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010061 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062
10063 // Check for constructor frame.
10064 bool constructor = it.frame()->IsConstructor();
10065
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010066 // Get scope info and read from it for local variable information.
10067 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010068 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010069 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010070 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072 // Get the locals names and values into a temporary array.
10073 //
10074 // TODO(1240907): Hide compiler-introduced stack variables
10075 // (e.g. .result)? For users of the debugger, they will probably be
10076 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010077 Handle<FixedArray> locals =
10078 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010080 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010081 int i = 0;
10082 for (; i < info.number_of_stack_slots(); ++i) {
10083 // Use the value from the stack.
10084 locals->set(i * 2, *info.LocalName(i));
10085 if (it.frame()->is_optimized()) {
10086 // Get the value from the deoptimized frame.
10087 locals->set(i * 2 + 1,
10088 deoptimized_frame->GetExpression(i));
10089 } else {
10090 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010092 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010093 }
10094 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010095 // Get the context containing declarations.
10096 Handle<Context> context(
10097 Context::cast(it.frame()->context())->declaration_context());
10098 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010099 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010100 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010102 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 }
10104 }
10105
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010106 // Check whether this frame is positioned at return. If not top
10107 // frame or if the frame is optimized it cannot be at a return.
10108 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010109 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010110 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010111 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010112
10113 // If positioned just before return find the value to be returned and add it
10114 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010116 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010117 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010118 Address internal_frame_sp = NULL;
10119 while (!it2.done()) {
10120 if (it2.frame()->is_internal()) {
10121 internal_frame_sp = it2.frame()->sp();
10122 } else {
10123 if (it2.frame()->is_java_script()) {
10124 if (it2.frame()->id() == it.frame()->id()) {
10125 // The internal frame just before the JavaScript frame contains the
10126 // value to return on top. A debug break at return will create an
10127 // internal frame to store the return value (eax/rax/r0) before
10128 // entering the debug break exit frame.
10129 if (internal_frame_sp != NULL) {
10130 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010131 Handle<Object>(Memory::Object_at(internal_frame_sp),
10132 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010133 break;
10134 }
10135 }
10136 }
10137
10138 // Indicate that the previous frame was not an internal frame.
10139 internal_frame_sp = NULL;
10140 }
10141 it2.Advance();
10142 }
10143 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144
10145 // Now advance to the arguments adapter frame (if any). It contains all
10146 // the provided parameters whereas the function frame always have the number
10147 // of arguments matching the functions parameters. The rest of the
10148 // information (except for what is collected above) is the same.
10149 it.AdvanceToArgumentsFrame();
10150
10151 // Find the number of arguments to fill. At least fill the number of
10152 // parameters for the function and fill more if more parameters are provided.
10153 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010154 if (argument_count < it.frame()->ComputeParametersCount()) {
10155 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156 }
10157
10158 // Calculate the size of the result.
10159 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010160 2 * (argument_count + info.NumberOfLocals()) +
10161 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010162 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163
10164 // Add the frame id.
10165 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10166
10167 // Add the function (same as in function frame).
10168 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
10169
10170 // Add the arguments count.
10171 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10172
10173 // Add the locals count
10174 details->set(kFrameDetailsLocalCountIndex,
10175 Smi::FromInt(info.NumberOfLocals()));
10176
10177 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010178 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10180 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010182 }
10183
10184 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010185 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010187 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010189
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010190 // Add flags to indicate information on whether this frame is
10191 // bit 0: invoked in the debugger context.
10192 // bit 1: optimized frame.
10193 // bit 2: inlined in optimized frame
10194 int flags = 0;
10195 if (*save->context() == *isolate->debug()->debug_context()) {
10196 flags |= 1 << 0;
10197 }
10198 if (it.frame()->is_optimized()) {
10199 flags |= 1 << 1;
10200 if (deoptimized_frame_index > 0) {
10201 flags |= 1 << 2;
10202 }
10203 }
10204 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205
10206 // Fill the dynamic part.
10207 int details_index = kFrameDetailsFirstDynamicIndex;
10208
10209 // Add arguments name and value.
10210 for (int i = 0; i < argument_count; i++) {
10211 // Name of the argument.
10212 if (i < info.number_of_parameters()) {
10213 details->set(details_index++, *info.parameter_name(i));
10214 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010215 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216 }
10217
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010218 // Parameter value. If we are inspecting an optimized frame, use
10219 // undefined as the value.
10220 //
10221 // TODO(3141533): We should be able to get the actual parameter
10222 // value for optimized frames.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010223 if (!it.frame()->is_optimized() &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010224 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 details->set(details_index++, it.frame()->GetParameter(i));
10226 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 }
10229 }
10230
10231 // Add locals name and value from the temporary copy from the function frame.
10232 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10233 details->set(details_index++, locals->get(i));
10234 }
10235
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010236 // Add the value being returned.
10237 if (at_return) {
10238 details->set(details_index++, *return_value);
10239 }
10240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 // Add the receiver (same as in function frame).
10242 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10243 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 if (!receiver->IsJSObject()) {
10246 // If the receiver is NOT a JSObject we have hit an optimization
10247 // where a value object is not converted into a wrapped JS objects.
10248 // To hide this optimization from the debugger, we wrap the receiver
10249 // by creating correct wrapper object based on the calling frame's
10250 // global context.
10251 it.Advance();
10252 Handle<Context> calling_frames_global_context(
10253 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 receiver =
10255 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 }
10257 details->set(kFrameDetailsReceiverIndex, *receiver);
10258
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010259 // Get rid of the calculated deoptimized frame if any.
10260 if (deoptimized_frame != NULL) {
10261 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame,
10262 isolate);
10263 }
10264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267}
10268
10269
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010270// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010271static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010272 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010273 Handle<SerializedScopeInfo> serialized_scope_info,
10274 ScopeInfo<>& scope_info,
10275 Handle<Context> context,
10276 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010277 // Fill all context locals to the context extension.
10278 for (int i = Context::MIN_CONTEXT_SLOTS;
10279 i < scope_info.number_of_context_slots();
10280 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010281 int context_index = serialized_scope_info->ContextSlotIndex(
10282 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010283
whesse@chromium.org7b260152011-06-20 15:33:18 +000010284 RETURN_IF_EMPTY_HANDLE_VALUE(
10285 isolate,
10286 SetProperty(scope_object,
10287 scope_info.context_slot_name(i),
10288 Handle<Object>(context->get(context_index), isolate),
10289 NONE,
10290 kNonStrictMode),
10291 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010292 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010293
10294 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010295}
10296
10297
10298// Create a plain JSObject which materializes the local scope for the specified
10299// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010300static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10301 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010302 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010303 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010304 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10305 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010306
10307 // Allocate and initialize a JSObject with all the arguments, stack locals
10308 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010309 Handle<JSObject> local_scope =
10310 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010311
10312 // First fill all parameters.
10313 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010314 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010316 SetProperty(local_scope,
10317 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010319 NONE,
10320 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010321 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010322 }
10323
10324 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010325 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010326 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010328 SetProperty(local_scope,
10329 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010331 NONE,
10332 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010333 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010334 }
10335
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010336 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10337 // Third fill all context locals.
10338 Handle<Context> frame_context(Context::cast(frame->context()));
10339 Handle<Context> function_context(frame_context->declaration_context());
10340 if (!CopyContextLocalsToScopeObject(isolate,
10341 serialized_scope_info, scope_info,
10342 function_context, local_scope)) {
10343 return Handle<JSObject>();
10344 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010345
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010346 // Finally copy any properties from the function context extension.
10347 // These will be variables introduced by eval.
10348 if (function_context->closure() == *function) {
10349 if (function_context->has_extension() &&
10350 !function_context->IsGlobalContext()) {
10351 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10352 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10353 for (int i = 0; i < keys->length(); i++) {
10354 // Names of variables introduced by eval are strings.
10355 ASSERT(keys->get(i)->IsString());
10356 Handle<String> key(String::cast(keys->get(i)));
10357 RETURN_IF_EMPTY_HANDLE_VALUE(
10358 isolate,
10359 SetProperty(local_scope,
10360 key,
10361 GetProperty(ext, key),
10362 NONE,
10363 kNonStrictMode),
10364 Handle<JSObject>());
10365 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010366 }
10367 }
10368 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010369
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010370 return local_scope;
10371}
10372
10373
10374// Create a plain JSObject which materializes the closure content for the
10375// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010376static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10377 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010378 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010379
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010380 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010381 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10382 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010383
10384 // Allocate and initialize a JSObject with all the content of theis function
10385 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 Handle<JSObject> closure_scope =
10387 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010388
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010389 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 if (!CopyContextLocalsToScopeObject(isolate,
10391 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010392 context, closure_scope)) {
10393 return Handle<JSObject>();
10394 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010395
10396 // Finally copy any properties from the function context extension. This will
10397 // be variables introduced by eval.
10398 if (context->has_extension()) {
10399 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010400 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010401 for (int i = 0; i < keys->length(); i++) {
10402 // Names of variables introduced by eval are strings.
10403 ASSERT(keys->get(i)->IsString());
10404 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010405 RETURN_IF_EMPTY_HANDLE_VALUE(
10406 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010407 SetProperty(closure_scope,
10408 key,
10409 GetProperty(ext, key),
10410 NONE,
10411 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010412 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010413 }
10414 }
10415
10416 return closure_scope;
10417}
10418
10419
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010420// Create a plain JSObject which materializes the scope for the specified
10421// catch context.
10422static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10423 Handle<Context> context) {
10424 ASSERT(context->IsCatchContext());
10425 Handle<String> name(String::cast(context->extension()));
10426 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10427 Handle<JSObject> catch_scope =
10428 isolate->factory()->NewJSObject(isolate->object_function());
10429 RETURN_IF_EMPTY_HANDLE_VALUE(
10430 isolate,
10431 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10432 Handle<JSObject>());
10433 return catch_scope;
10434}
10435
10436
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010437// Iterate over the actual scopes visible from a stack frame. All scopes are
10438// backed by an actual context except the local scope, which is inserted
10439// "artifically" in the context chain.
10440class ScopeIterator {
10441 public:
10442 enum ScopeType {
10443 ScopeTypeGlobal = 0,
10444 ScopeTypeLocal,
10445 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010446 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010447 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010448 };
10449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10451 : isolate_(isolate),
10452 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010453 function_(JSFunction::cast(frame->function())),
10454 context_(Context::cast(frame->context())),
10455 local_done_(false),
10456 at_local_(false) {
10457
10458 // Check whether the first scope is actually a local scope.
10459 if (context_->IsGlobalContext()) {
10460 // If there is a stack slot for .result then this local scope has been
10461 // created for evaluating top level code and it is not a real local scope.
10462 // Checking for the existence of .result seems fragile, but the scope info
10463 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010464 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010465 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010466 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010467 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010468 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010469 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010470 // The context_ is a with or catch block from the outer function.
10471 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010472 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010473 }
10474 }
10475
10476 // More scopes?
10477 bool Done() { return context_.is_null(); }
10478
10479 // Move to the next scope.
10480 void Next() {
10481 // If at a local scope mark the local scope as passed.
10482 if (at_local_) {
10483 at_local_ = false;
10484 local_done_ = true;
10485
10486 // If the current context is not associated with the local scope the
10487 // current context is the next real scope, so don't move to the next
10488 // context in this case.
10489 if (context_->closure() != *function_) {
10490 return;
10491 }
10492 }
10493
10494 // The global scope is always the last in the chain.
10495 if (context_->IsGlobalContext()) {
10496 context_ = Handle<Context>();
10497 return;
10498 }
10499
10500 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010501 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010502
10503 // If passing the local scope indicate that the current scope is now the
10504 // local scope.
10505 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010506 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010507 at_local_ = true;
10508 }
10509 }
10510
10511 // Return the type of the current scope.
10512 int Type() {
10513 if (at_local_) {
10514 return ScopeTypeLocal;
10515 }
10516 if (context_->IsGlobalContext()) {
10517 ASSERT(context_->global()->IsGlobalObject());
10518 return ScopeTypeGlobal;
10519 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010520 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010521 return ScopeTypeClosure;
10522 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010523 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010524 return ScopeTypeCatch;
10525 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010526 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010527 return ScopeTypeWith;
10528 }
10529
10530 // Return the JavaScript object with the content of the current scope.
10531 Handle<JSObject> ScopeObject() {
10532 switch (Type()) {
10533 case ScopeIterator::ScopeTypeGlobal:
10534 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010535 case ScopeIterator::ScopeTypeLocal:
10536 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010538 case ScopeIterator::ScopeTypeWith:
10539 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010540 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10541 case ScopeIterator::ScopeTypeCatch:
10542 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010543 case ScopeIterator::ScopeTypeClosure:
10544 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010545 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010546 }
10547 UNREACHABLE();
10548 return Handle<JSObject>();
10549 }
10550
10551 // Return the context for this scope. For the local context there might not
10552 // be an actual context.
10553 Handle<Context> CurrentContext() {
10554 if (at_local_ && context_->closure() != *function_) {
10555 return Handle<Context>();
10556 }
10557 return context_;
10558 }
10559
10560#ifdef DEBUG
10561 // Debug print of the content of the current scope.
10562 void DebugPrint() {
10563 switch (Type()) {
10564 case ScopeIterator::ScopeTypeGlobal:
10565 PrintF("Global:\n");
10566 CurrentContext()->Print();
10567 break;
10568
10569 case ScopeIterator::ScopeTypeLocal: {
10570 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010571 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010572 scope_info.Print();
10573 if (!CurrentContext().is_null()) {
10574 CurrentContext()->Print();
10575 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010576 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010577 if (extension->IsJSContextExtensionObject()) {
10578 extension->Print();
10579 }
10580 }
10581 }
10582 break;
10583 }
10584
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010585 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010586 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010587 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010588 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010590 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010591 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010592 CurrentContext()->extension()->Print();
10593 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010594 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010595
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010596 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010597 PrintF("Closure:\n");
10598 CurrentContext()->Print();
10599 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010600 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010601 if (extension->IsJSContextExtensionObject()) {
10602 extension->Print();
10603 }
10604 }
10605 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010606
10607 default:
10608 UNREACHABLE();
10609 }
10610 PrintF("\n");
10611 }
10612#endif
10613
10614 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010616 JavaScriptFrame* frame_;
10617 Handle<JSFunction> function_;
10618 Handle<Context> context_;
10619 bool local_done_;
10620 bool at_local_;
10621
10622 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10623};
10624
10625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010626RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010628 ASSERT(args.length() == 2);
10629
10630 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010631 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010632 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10633 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010634 if (!maybe_check->ToObject(&check)) return maybe_check;
10635 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010636 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10637
10638 // Get the frame where the debugging is performed.
10639 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010640 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010641 JavaScriptFrame* frame = it.frame();
10642
10643 // Count the visible scopes.
10644 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010646 n++;
10647 }
10648
10649 return Smi::FromInt(n);
10650}
10651
10652
10653static const int kScopeDetailsTypeIndex = 0;
10654static const int kScopeDetailsObjectIndex = 1;
10655static const int kScopeDetailsSize = 2;
10656
10657// Return an array with scope details
10658// args[0]: number: break id
10659// args[1]: number: frame index
10660// args[2]: number: scope index
10661//
10662// The array returned contains the following information:
10663// 0: Scope type
10664// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010665RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010666 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010667 ASSERT(args.length() == 3);
10668
10669 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010670 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010671 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10672 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010673 if (!maybe_check->ToObject(&check)) return maybe_check;
10674 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010675 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10676 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10677
10678 // Get the frame where the debugging is performed.
10679 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010680 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010681 JavaScriptFrame* frame = frame_it.frame();
10682
10683 // Find the requested scope.
10684 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010685 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010686 for (; !it.Done() && n < index; it.Next()) {
10687 n++;
10688 }
10689 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010690 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010691 }
10692
10693 // Calculate the size of the result.
10694 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010696
10697 // Fill in scope details.
10698 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010699 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010700 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010701 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010703 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010704}
10705
10706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010707RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010709 ASSERT(args.length() == 0);
10710
10711#ifdef DEBUG
10712 // Print the scopes for the top frame.
10713 StackFrameLocator locator;
10714 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010715 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010716 it.DebugPrint();
10717 }
10718#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010719 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010720}
10721
10722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010723RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010724 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010725 ASSERT(args.length() == 1);
10726
10727 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010728 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010729 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10730 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010731 if (!maybe_result->ToObject(&result)) return maybe_result;
10732 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010733
10734 // Count all archived V8 threads.
10735 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736 for (ThreadState* thread =
10737 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010738 thread != NULL;
10739 thread = thread->Next()) {
10740 n++;
10741 }
10742
10743 // Total number of threads is current thread and archived threads.
10744 return Smi::FromInt(n + 1);
10745}
10746
10747
10748static const int kThreadDetailsCurrentThreadIndex = 0;
10749static const int kThreadDetailsThreadIdIndex = 1;
10750static const int kThreadDetailsSize = 2;
10751
10752// Return an array with thread details
10753// args[0]: number: break id
10754// args[1]: number: thread index
10755//
10756// The array returned contains the following information:
10757// 0: Is current thread?
10758// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010759RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010761 ASSERT(args.length() == 2);
10762
10763 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010764 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010765 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10766 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010767 if (!maybe_check->ToObject(&check)) return maybe_check;
10768 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010769 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10770
10771 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 Handle<FixedArray> details =
10773 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010774
10775 // Thread index 0 is current thread.
10776 if (index == 0) {
10777 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 details->set(kThreadDetailsCurrentThreadIndex,
10779 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010780 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010781 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010782 } else {
10783 // Find the thread with the requested index.
10784 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 ThreadState* thread =
10786 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010787 while (index != n && thread != NULL) {
10788 thread = thread->Next();
10789 n++;
10790 }
10791 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010793 }
10794
10795 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 details->set(kThreadDetailsCurrentThreadIndex,
10797 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010798 details->set(kThreadDetailsThreadIdIndex,
10799 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010800 }
10801
10802 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010804}
10805
10806
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010807// Sets the disable break state
10808// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010809RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010810 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010811 ASSERT(args.length() == 1);
10812 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 isolate->debug()->set_disable_break(disable_break);
10814 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010815}
10816
10817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010818RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 ASSERT(args.length() == 1);
10821
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010822 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10823 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824 // Find the number of break points
10825 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010828 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829 Handle<FixedArray>::cast(break_locations));
10830}
10831
10832
10833// Set a break point in a function
10834// args[0]: function
10835// args[1]: number: break source position (within the function source)
10836// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010837RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010840 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10841 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10843 RUNTIME_ASSERT(source_position >= 0);
10844 Handle<Object> break_point_object_arg = args.at<Object>(2);
10845
10846 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10848 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010850 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851}
10852
10853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10855 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010856 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857 // Iterate the heap looking for SharedFunctionInfo generated from the
10858 // script. The inner most SharedFunctionInfo containing the source position
10859 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010860 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861 // which is found is not compiled it is compiled and the heap is iterated
10862 // again as the compilation might create inner functions from the newly
10863 // compiled function and the actual requested break point might be in one of
10864 // these functions.
10865 bool done = false;
10866 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010867 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 while (!done) {
10870 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010871 for (HeapObject* obj = iterator.next();
10872 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 if (obj->IsSharedFunctionInfo()) {
10874 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10875 if (shared->script() == *script) {
10876 // If the SharedFunctionInfo found has the requested script data and
10877 // contains the source position it is a candidate.
10878 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010879 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 start_position = shared->start_position();
10881 }
10882 if (start_position <= position &&
10883 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010884 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 // candidate this is the new candidate.
10886 if (target.is_null()) {
10887 target_start_position = start_position;
10888 target = shared;
10889 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010890 if (target_start_position == start_position &&
10891 shared->end_position() == target->end_position()) {
10892 // If a top-level function contain only one function
10893 // declartion the source for the top-level and the function is
10894 // the same. In that case prefer the non top-level function.
10895 if (!shared->is_toplevel()) {
10896 target_start_position = start_position;
10897 target = shared;
10898 }
10899 } else if (target_start_position <= start_position &&
10900 shared->end_position() <= target->end_position()) {
10901 // This containment check includes equality as a function inside
10902 // a top-level function can share either start or end position
10903 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904 target_start_position = start_position;
10905 target = shared;
10906 }
10907 }
10908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909 }
10910 }
10911 }
10912
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010914 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010915 }
10916
10917 // If the candidate found is compiled we are done. NOTE: when lazy
10918 // compilation of inner functions is introduced some additional checking
10919 // needs to be done here to compile inner functions.
10920 done = target->is_compiled();
10921 if (!done) {
10922 // If the candidate is not compiled compile it to reveal any inner
10923 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010924 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 }
10926 }
10927
10928 return *target;
10929}
10930
10931
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010932// Changes the state of a break point in a script and returns source position
10933// where break point was set. NOTE: Regarding performance see the NOTE for
10934// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935// args[0]: script to set break point in
10936// args[1]: number: break source position (within the script source)
10937// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010938RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940 ASSERT(args.length() == 3);
10941 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10942 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10943 RUNTIME_ASSERT(source_position >= 0);
10944 Handle<Object> break_point_object_arg = args.at<Object>(2);
10945
10946 // Get the script from the script wrapper.
10947 RUNTIME_ASSERT(wrapper->value()->IsScript());
10948 Handle<Script> script(Script::cast(wrapper->value()));
10949
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010950 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 if (!result->IsUndefined()) {
10953 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10954 // Find position within function. The script position might be before the
10955 // source position of the first function.
10956 int position;
10957 if (shared->start_position() > source_position) {
10958 position = 0;
10959 } else {
10960 position = source_position - shared->start_position();
10961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010963 position += shared->start_position();
10964 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967}
10968
10969
10970// Clear a break point
10971// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010972RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010973 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 ASSERT(args.length() == 1);
10975 Handle<Object> break_point_object_arg = args.at<Object>(0);
10976
10977 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981}
10982
10983
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010984// Change the state of break on exceptions.
10985// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10986// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010987RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010988 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010989 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010990 RUNTIME_ASSERT(args[0]->IsNumber());
10991 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010993 // If the number doesn't match an enum value, the ChangeBreakOnException
10994 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995 ExceptionBreakType type =
10996 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010997 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 isolate->debug()->ChangeBreakOnException(type, enable);
10999 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000}
11001
11002
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011003// Returns the state of break on exceptions
11004// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011005RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011006 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011007 ASSERT(args.length() == 1);
11008 RUNTIME_ASSERT(args[0]->IsNumber());
11009
11010 ExceptionBreakType type =
11011 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011013 return Smi::FromInt(result);
11014}
11015
11016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017// Prepare for stepping
11018// args[0]: break id for checking execution state
11019// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011020// args[2]: number of times to perform the step, for step out it is the number
11021// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011022RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011023 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 ASSERT(args.length() == 3);
11025 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011026 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011027 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11028 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011029 if (!maybe_check->ToObject(&check)) return maybe_check;
11030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011031 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011032 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 }
11034
11035 // Get the step action and check validity.
11036 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11037 if (step_action != StepIn &&
11038 step_action != StepNext &&
11039 step_action != StepOut &&
11040 step_action != StepInMin &&
11041 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 }
11044
11045 // Get the number of steps.
11046 int step_count = NumberToInt32(args[2]);
11047 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011049 }
11050
ager@chromium.orga1645e22009-09-09 19:27:10 +000011051 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011052 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11056 step_count);
11057 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058}
11059
11060
11061// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011062RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011063 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011064 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 isolate->debug()->ClearStepping();
11066 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067}
11068
11069
11070// Creates a copy of the with context chain. The copy of the context chain is
11071// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011072static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011073 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011074 Handle<Context> current,
11075 Handle<Context> base) {
11076 // At the end of the chain. Return the base context to link to.
11077 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11078 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079 }
11080
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011081 // Recursively copy the with and catch contexts.
11082 HandleScope scope(isolate);
11083 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011084 Handle<Context> new_previous =
11085 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011086 Handle<Context> new_current;
11087 if (current->IsCatchContext()) {
11088 Handle<String> name(String::cast(current->extension()));
11089 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11090 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011091 isolate->factory()->NewCatchContext(function,
11092 new_previous,
11093 name,
11094 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011095 } else {
11096 Handle<JSObject> extension(JSObject::cast(current->extension()));
11097 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011098 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011099 }
11100 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101}
11102
11103
11104// Helper function to find or create the arguments object for
11105// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106static Handle<Object> GetArgumentsObject(Isolate* isolate,
11107 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011109 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011110 const ScopeInfo<>* sinfo,
11111 Handle<Context> function_context) {
11112 // Try to find the value of 'arguments' to pass as parameter. If it is not
11113 // found (that is the debugged function does not reference 'arguments' and
11114 // does not support eval) then create an 'arguments' object.
11115 int index;
11116 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011118 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011120 }
11121 }
11122
11123 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11125 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011127 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128 }
11129 }
11130
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011131 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011132 Handle<JSObject> arguments =
11133 isolate->factory()->NewArgumentsObject(function, length);
11134 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011135
11136 AssertNoAllocation no_gc;
11137 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011139 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011141 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142 return arguments;
11143}
11144
11145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011146static const char kSourceStr[] =
11147 "(function(arguments,__source__){return eval(__source__);})";
11148
11149
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011151// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152// extension part has all the parameters and locals of the function on the
11153// stack frame. A function which calls eval with the code to evaluate is then
11154// compiled in this context and called in this context. As this context
11155// replaces the context of the function on the stack frame a new (empty)
11156// function is created as well to be used as the closure for the context.
11157// This function and the context acts as replacements for the function on the
11158// stack frame presenting the same view of the values of parameters and
11159// local variables as if the piece of JavaScript was evaluated at the point
11160// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011161RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011163
11164 // Check the execution state and decode arguments frame and source to be
11165 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011166 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011167 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011168 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11169 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011170 if (!maybe_check_result->ToObject(&check_result)) {
11171 return maybe_check_result;
11172 }
11173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11175 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011176 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011177 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011178
11179 // Handle the processing of break.
11180 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181
11182 // Get the frame where the debugging is performed.
11183 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011184 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 JavaScriptFrame* frame = it.frame();
11186 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011187 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011188 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011189
11190 // Traverse the saved contexts chain to find the active context for the
11191 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011192 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011193 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194 save = save->prev();
11195 }
11196 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 SaveContext savex(isolate);
11198 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011199
11200 // Create the (empty) function replacing the function on the stack frame for
11201 // the purpose of evaluating in the context created below. It is important
11202 // that this function does not describe any parameters and local variables
11203 // in the context. If it does then this will cause problems with the lookup
11204 // in Context::Lookup, where context slots for parameters and local variables
11205 // are looked at before the extension object.
11206 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11208 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209 go_between->set_context(function->context());
11210#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011211 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11213 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11214#endif
11215
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011216 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011217 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11218 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011219
11220 // Allocate a new context for the debug evaluation and set the extension
11221 // object build.
11222 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011223 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11224 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011225 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011226 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011227 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011228 Handle<Context> function_context(frame_context->declaration_context());
11229 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011230
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011231 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011232 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011233 context =
11234 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011235 }
11236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011237 // Wrap the evaluation statement in a new function compiled in the newly
11238 // created context. The function has one parameter which has to be called
11239 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011240 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011241 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011242
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011244 isolate->factory()->NewStringFromAscii(
11245 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011246
11247 // Currently, the eval code will be executed in non-strict mode,
11248 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011249 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011250 Compiler::CompileEval(function_source,
11251 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011252 context->IsGlobalContext(),
11253 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011254 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011257
11258 // Invoke the result of the compilation to get the evaluation function.
11259 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011260 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011261 Handle<Object> evaluation_function =
11262 Execution::Call(compiled_function, receiver, 0, NULL,
11263 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011264 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011266 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11267 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011268 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269
11270 // Invoke the evaluation function and return the result.
11271 const int argc = 2;
11272 Object** argv[argc] = { arguments.location(),
11273 Handle<Object>::cast(source).location() };
11274 Handle<Object> result =
11275 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11276 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011277 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011278
11279 // Skip the global proxy as it has no properties and always delegates to the
11280 // real global object.
11281 if (result->IsJSGlobalProxy()) {
11282 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11283 }
11284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011285 return *result;
11286}
11287
11288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011290 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011291
11292 // Check the execution state and decode arguments frame and source to be
11293 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011294 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011295 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011296 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11297 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011298 if (!maybe_check_result->ToObject(&check_result)) {
11299 return maybe_check_result;
11300 }
11301 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011302 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011303 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011304 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011305
11306 // Handle the processing of break.
11307 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011308
11309 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011311 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011313 top = top->prev();
11314 }
11315 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011317 }
11318
11319 // Get the global context now set to the top context from before the
11320 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011321 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011322
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011323 bool is_global = true;
11324
11325 if (additional_context->IsJSObject()) {
11326 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11328 isolate->factory()->empty_string(),
11329 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011330 go_between->set_context(*context);
11331 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 isolate->factory()->NewFunctionContext(
11333 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011334 context->set_extension(JSObject::cast(*additional_context));
11335 is_global = false;
11336 }
11337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011339 // Currently, the eval code will be executed in non-strict mode,
11340 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011341 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011342 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011343 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011344 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 Handle<JSFunction>(
11346 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11347 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011348
11349 // Invoke the result of the compilation to get the evaluation function.
11350 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011352 Handle<Object> result =
11353 Execution::Call(compiled_function, receiver, 0, NULL,
11354 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011355 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 return *result;
11357}
11358
11359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011360RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011361 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011362 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011363
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011364 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011366
11367 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011368 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011369 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11370 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11371 // because using
11372 // instances->set(i, *GetScriptWrapper(script))
11373 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11374 // already have deferenced the instances handle.
11375 Handle<JSValue> wrapper = GetScriptWrapper(script);
11376 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011377 }
11378
11379 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 Handle<JSObject> result =
11381 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011382 Handle<JSArray>::cast(result)->SetContent(*instances);
11383 return *result;
11384}
11385
11386
11387// Helper function used by Runtime_DebugReferencedBy below.
11388static int DebugReferencedBy(JSObject* target,
11389 Object* instance_filter, int max_references,
11390 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011391 JSFunction* arguments_function) {
11392 NoHandleAllocation ha;
11393 AssertNoAllocation no_alloc;
11394
11395 // Iterate the heap.
11396 int count = 0;
11397 JSObject* last = NULL;
11398 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011399 HeapObject* heap_obj = NULL;
11400 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011401 (max_references == 0 || count < max_references)) {
11402 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011403 if (heap_obj->IsJSObject()) {
11404 // Skip context extension objects and argument arrays as these are
11405 // checked in the context of functions using them.
11406 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011407 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011408 obj->map()->constructor() == arguments_function) {
11409 continue;
11410 }
11411
11412 // Check if the JS object has a reference to the object looked for.
11413 if (obj->ReferencesObject(target)) {
11414 // Check instance filter if supplied. This is normally used to avoid
11415 // references from mirror objects (see Runtime_IsInPrototypeChain).
11416 if (!instance_filter->IsUndefined()) {
11417 Object* V = obj;
11418 while (true) {
11419 Object* prototype = V->GetPrototype();
11420 if (prototype->IsNull()) {
11421 break;
11422 }
11423 if (instance_filter == prototype) {
11424 obj = NULL; // Don't add this object.
11425 break;
11426 }
11427 V = prototype;
11428 }
11429 }
11430
11431 if (obj != NULL) {
11432 // Valid reference found add to instance array if supplied an update
11433 // count.
11434 if (instances != NULL && count < instances_size) {
11435 instances->set(count, obj);
11436 }
11437 last = obj;
11438 count++;
11439 }
11440 }
11441 }
11442 }
11443
11444 // Check for circular reference only. This can happen when the object is only
11445 // referenced from mirrors and has a circular reference in which case the
11446 // object is not really alive and would have been garbage collected if not
11447 // referenced from the mirror.
11448 if (count == 1 && last == target) {
11449 count = 0;
11450 }
11451
11452 // Return the number of referencing objects found.
11453 return count;
11454}
11455
11456
11457// Scan the heap for objects with direct references to an object
11458// args[0]: the object to find references to
11459// args[1]: constructor function for instances to exclude (Mirror)
11460// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011461RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011462 ASSERT(args.length() == 3);
11463
11464 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011465 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466
11467 // Check parameters.
11468 CONVERT_CHECKED(JSObject, target, args[0]);
11469 Object* instance_filter = args[1];
11470 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11471 instance_filter->IsJSObject());
11472 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11473 RUNTIME_ASSERT(max_references >= 0);
11474
11475 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011476 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478 JSFunction* arguments_function =
11479 JSFunction::cast(arguments_boilerplate->map()->constructor());
11480
11481 // Get the number of referencing objects.
11482 int count;
11483 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011484 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011485
11486 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011487 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011488 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011489 if (!maybe_object->ToObject(&object)) return maybe_object;
11490 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491 FixedArray* instances = FixedArray::cast(object);
11492
11493 // Fill the referencing objects.
11494 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011495 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011496
11497 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011498 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11500 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011501 if (!maybe_result->ToObject(&result)) return maybe_result;
11502 }
11503 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011504 return result;
11505}
11506
11507
11508// Helper function used by Runtime_DebugConstructedBy below.
11509static int DebugConstructedBy(JSFunction* constructor, int max_references,
11510 FixedArray* instances, int instances_size) {
11511 AssertNoAllocation no_alloc;
11512
11513 // Iterate the heap.
11514 int count = 0;
11515 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011516 HeapObject* heap_obj = NULL;
11517 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 (max_references == 0 || count < max_references)) {
11519 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520 if (heap_obj->IsJSObject()) {
11521 JSObject* obj = JSObject::cast(heap_obj);
11522 if (obj->map()->constructor() == constructor) {
11523 // Valid reference found add to instance array if supplied an update
11524 // count.
11525 if (instances != NULL && count < instances_size) {
11526 instances->set(count, obj);
11527 }
11528 count++;
11529 }
11530 }
11531 }
11532
11533 // Return the number of referencing objects found.
11534 return count;
11535}
11536
11537
11538// Scan the heap for objects constructed by a specific function.
11539// args[0]: the constructor to find instances of
11540// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 ASSERT(args.length() == 2);
11543
11544 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011545 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011546
11547 // Check parameters.
11548 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11549 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11550 RUNTIME_ASSERT(max_references >= 0);
11551
11552 // Get the number of referencing objects.
11553 int count;
11554 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11555
11556 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011557 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011559 if (!maybe_object->ToObject(&object)) return maybe_object;
11560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011561 FixedArray* instances = FixedArray::cast(object);
11562
11563 // Fill the referencing objects.
11564 count = DebugConstructedBy(constructor, max_references, instances, count);
11565
11566 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011567 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11569 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011570 if (!maybe_result->ToObject(&result)) return maybe_result;
11571 }
11572 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011573 return result;
11574}
11575
11576
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011577// Find the effective prototype object as returned by __proto__.
11578// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011579RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580 ASSERT(args.length() == 1);
11581
11582 CONVERT_CHECKED(JSObject, obj, args[0]);
11583
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011584 // Use the __proto__ accessor.
11585 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011586}
11587
11588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011589RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011590 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011592 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593}
11594
11595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011596RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011597#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011598 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011599 ASSERT(args.length() == 1);
11600 // Get the function and make sure it is compiled.
11601 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011602 Handle<SharedFunctionInfo> shared(func->shared());
11603 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011604 return Failure::Exception();
11605 }
11606 func->code()->PrintLn();
11607#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011609}
ager@chromium.org9085a012009-05-11 19:22:57 +000011610
11611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011612RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011613#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011615 ASSERT(args.length() == 1);
11616 // Get the function and make sure it is compiled.
11617 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011618 Handle<SharedFunctionInfo> shared(func->shared());
11619 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011620 return Failure::Exception();
11621 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011622 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011623#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011624 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011625}
11626
11627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011628RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011629 NoHandleAllocation ha;
11630 ASSERT(args.length() == 1);
11631
11632 CONVERT_CHECKED(JSFunction, f, args[0]);
11633 return f->shared()->inferred_name();
11634}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011635
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011636
11637static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011639 AssertNoAllocation no_allocations;
11640
11641 int counter = 0;
11642 int buffer_size = buffer->length();
11643 HeapIterator iterator;
11644 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11645 ASSERT(obj != NULL);
11646 if (!obj->IsSharedFunctionInfo()) {
11647 continue;
11648 }
11649 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11650 if (shared->script() != script) {
11651 continue;
11652 }
11653 if (counter < buffer_size) {
11654 buffer->set(counter, shared);
11655 }
11656 counter++;
11657 }
11658 return counter;
11659}
11660
11661// For a script finds all SharedFunctionInfo's in the heap that points
11662// to this script. Returns JSArray of SharedFunctionInfo wrapped
11663// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011664RUNTIME_FUNCTION(MaybeObject*,
11665 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011666 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011668 CONVERT_CHECKED(JSValue, script_value, args[0]);
11669
11670 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11671
11672 const int kBufferSize = 32;
11673
11674 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011676 int number = FindSharedFunctionInfosForScript(*script, *array);
11677 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011679 FindSharedFunctionInfosForScript(*script, *array);
11680 }
11681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011683 result->set_length(Smi::FromInt(number));
11684
11685 LiveEdit::WrapSharedFunctionInfos(result);
11686
11687 return *result;
11688}
11689
11690// For a script calculates compilation information about all its functions.
11691// The script source is explicitly specified by the second argument.
11692// The source of the actual script is not used, however it is important that
11693// all generated code keeps references to this particular instance of script.
11694// Returns a JSArray of compilation infos. The array is ordered so that
11695// each function with all its descendant is always stored in a continues range
11696// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011697RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011698 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011700 CONVERT_CHECKED(JSValue, script, args[0]);
11701 CONVERT_ARG_CHECKED(String, source, 1);
11702 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11703
11704 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011706 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011707 return Failure::Exception();
11708 }
11709
11710 return result;
11711}
11712
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011713// Changes the source of the script to a new_source.
11714// If old_script_name is provided (i.e. is a String), also creates a copy of
11715// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011716RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011717 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011719 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11720 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011722
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011723 CONVERT_CHECKED(Script, original_script_pointer,
11724 original_script_value->value());
11725 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011726
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011727 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11728 new_source,
11729 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011730
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011731 if (old_script->IsScript()) {
11732 Handle<Script> script_handle(Script::cast(old_script));
11733 return *(GetScriptWrapper(script_handle));
11734 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011736 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011737}
11738
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011740RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011741 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011742 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011743 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11744 return LiveEdit::FunctionSourceUpdated(shared_info);
11745}
11746
11747
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011748// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011749RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011750 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011752 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11753 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11754
ager@chromium.orgac091b72010-05-05 07:34:42 +000011755 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011756}
11757
11758// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011759RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011760 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 HandleScope scope(isolate);
11762 Handle<Object> function_object(args[0], isolate);
11763 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011764
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011765 if (function_object->IsJSValue()) {
11766 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11767 if (script_object->IsJSValue()) {
11768 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011770 }
11771
11772 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11773 } else {
11774 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11775 // and we check it in this function.
11776 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011778 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011779}
11780
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011781
11782// In a code of a parent function replaces original function as embedded object
11783// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011784RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011785 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011787
11788 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11789 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11790 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11791
11792 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11793 subst_wrapper);
11794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011795 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011796}
11797
11798
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011799// Updates positions of a shared function info (first parameter) according
11800// to script source change. Text change is described in second parameter as
11801// array of groups of 3 numbers:
11802// (change_begin, change_end, change_end_new_position).
11803// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011804RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011805 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011806 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011807 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11808 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11809
ager@chromium.orgac091b72010-05-05 07:34:42 +000011810 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011811}
11812
11813
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011814// For array of SharedFunctionInfo's (each wrapped in JSValue)
11815// checks that none of them have activations on stacks (of any thread).
11816// Returns array of the same length with corresponding results of
11817// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011818RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011819 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011821 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011822 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011823
ager@chromium.org357bf652010-04-12 11:30:10 +000011824 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011825}
11826
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011827// Compares 2 strings line-by-line, then token-wise and returns diff in form
11828// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11829// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011830RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011831 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011833 CONVERT_ARG_CHECKED(String, s1, 0);
11834 CONVERT_ARG_CHECKED(String, s2, 1);
11835
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011836 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011837}
11838
11839
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011840// A testing entry. Returns statement position which is the closest to
11841// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011842RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011843 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011845 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11846 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011849
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011850 if (code->kind() != Code::FUNCTION &&
11851 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011853 }
11854
11855 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011856 int closest_pc = 0;
11857 int distance = kMaxInt;
11858 while (!it.done()) {
11859 int statement_position = static_cast<int>(it.rinfo()->data());
11860 // Check if this break point is closer that what was previously found.
11861 if (source_position <= statement_position &&
11862 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011863 closest_pc =
11864 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011865 distance = statement_position - source_position;
11866 // Check whether we can't get any closer.
11867 if (distance == 0) break;
11868 }
11869 it.next();
11870 }
11871
11872 return Smi::FromInt(closest_pc);
11873}
11874
11875
ager@chromium.org357bf652010-04-12 11:30:10 +000011876// Calls specified function with or without entering the debugger.
11877// This is used in unit tests to run code as if debugger is entered or simply
11878// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011879RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011880 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011882 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11883 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11884
11885 Handle<Object> result;
11886 bool pending_exception;
11887 {
11888 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011890 &pending_exception);
11891 } else {
11892 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011894 &pending_exception);
11895 }
11896 }
11897 if (!pending_exception) {
11898 return *result;
11899 } else {
11900 return Failure::Exception();
11901 }
11902}
11903
11904
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011905// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011906RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011907 CONVERT_CHECKED(String, arg, args[0]);
11908 SmartPointer<char> flags =
11909 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11910 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011912}
11913
11914
11915// Performs a GC.
11916// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011917RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011918 isolate->heap()->CollectAllGarbage(true);
11919 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011920}
11921
11922
11923// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011924RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011925 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011926 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011928 }
11929 return Smi::FromInt(usage);
11930}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011931
11932
11933// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011934RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011935#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011937#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011938 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011939#endif
11940}
11941
11942
11943// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011944RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011945#ifdef LIVE_OBJECT_LIST
11946 return LiveObjectList::Capture();
11947#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011949#endif
11950}
11951
11952
11953// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011955#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011956 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011957 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958 return success ? isolate->heap()->true_value() :
11959 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011960#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011962#endif
11963}
11964
11965
11966// Generates the response to a debugger request for a dump of the objects
11967// contained in the difference between the captured live object lists
11968// specified by id1 and id2.
11969// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11970// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011971RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011972#ifdef LIVE_OBJECT_LIST
11973 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011974 CONVERT_SMI_ARG_CHECKED(id1, 0);
11975 CONVERT_SMI_ARG_CHECKED(id2, 1);
11976 CONVERT_SMI_ARG_CHECKED(start, 2);
11977 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011978 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11979 EnterDebugger enter_debugger;
11980 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11981#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011983#endif
11984}
11985
11986
11987// Gets the specified object as requested by the debugger.
11988// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011989RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011990#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011991 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011992 Object* result = LiveObjectList::GetObj(obj_id);
11993 return result;
11994#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011996#endif
11997}
11998
11999
12000// Gets the obj id for the specified address if valid.
12001// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012002RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012003#ifdef LIVE_OBJECT_LIST
12004 HandleScope scope;
12005 CONVERT_ARG_CHECKED(String, address, 0);
12006 Object* result = LiveObjectList::GetObjId(address);
12007 return result;
12008#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012010#endif
12011}
12012
12013
12014// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012015RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012016#ifdef LIVE_OBJECT_LIST
12017 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012018 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012019 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12020 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12021 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12022 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12023 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12024
12025 Handle<JSObject> instance_filter;
12026 if (args[1]->IsJSObject()) {
12027 instance_filter = args.at<JSObject>(1);
12028 }
12029 bool verbose = false;
12030 if (args[2]->IsBoolean()) {
12031 verbose = args[2]->IsTrue();
12032 }
12033 int start = 0;
12034 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012035 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012036 }
12037 int limit = Smi::kMaxValue;
12038 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012039 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012040 }
12041
12042 return LiveObjectList::GetObjRetainers(obj_id,
12043 instance_filter,
12044 verbose,
12045 start,
12046 limit,
12047 filter_obj);
12048#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012049 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012050#endif
12051}
12052
12053
12054// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012055RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012056#ifdef LIVE_OBJECT_LIST
12057 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012058 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12059 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012060 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12061
12062 Handle<JSObject> instance_filter;
12063 if (args[2]->IsJSObject()) {
12064 instance_filter = args.at<JSObject>(2);
12065 }
12066
12067 Object* result =
12068 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12069 return result;
12070#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012071 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012072#endif
12073}
12074
12075
12076// Generates the response to a debugger request for a list of all
12077// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012078RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012079#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012080 CONVERT_SMI_ARG_CHECKED(start, 0);
12081 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012082 return LiveObjectList::Info(start, count);
12083#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012084 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012085#endif
12086}
12087
12088
12089// Gets a dump of the specified object as requested by the debugger.
12090// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012091RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012092#ifdef LIVE_OBJECT_LIST
12093 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012094 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012095 Object* result = LiveObjectList::PrintObj(obj_id);
12096 return result;
12097#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012099#endif
12100}
12101
12102
12103// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012104RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012105#ifdef LIVE_OBJECT_LIST
12106 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012108#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012109 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012110#endif
12111}
12112
12113
12114// Generates the response to a debugger request for a summary of the types
12115// of objects in the difference between the captured live object lists
12116// specified by id1 and id2.
12117// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12118// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012119RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012120#ifdef LIVE_OBJECT_LIST
12121 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012122 CONVERT_SMI_ARG_CHECKED(id1, 0);
12123 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012124 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12125
12126 EnterDebugger enter_debugger;
12127 return LiveObjectList::Summarize(id1, id2, filter_obj);
12128#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012130#endif
12131}
12132
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012133#endif // ENABLE_DEBUGGER_SUPPORT
12134
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012135
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012136#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012137RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012138 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012139 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012140 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012141}
12142
12143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012144RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012145 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012146 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012147 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012148}
12149
12150#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152// Finds the script object from the script data. NOTE: This operation uses
12153// heap traversal to find the function generated for the source position
12154// for the requested break point. For lazily compiled functions several heap
12155// traversals might be required rendering this operation as a rather slow
12156// operation. However for setting break points which is normally done through
12157// some kind of user interaction the performance is not crucial.
12158static Handle<Object> Runtime_GetScriptFromScriptName(
12159 Handle<String> script_name) {
12160 // Scan the heap for Script objects to find the script with the requested
12161 // script data.
12162 Handle<Script> script;
12163 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012164 HeapObject* obj = NULL;
12165 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166 // If a script is found check if it has the script data requested.
12167 if (obj->IsScript()) {
12168 if (Script::cast(obj)->name()->IsString()) {
12169 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12170 script = Handle<Script>(Script::cast(obj));
12171 }
12172 }
12173 }
12174 }
12175
12176 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012177 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178
12179 // Return the script found.
12180 return GetScriptWrapper(script);
12181}
12182
12183
12184// Get the script object from script data. NOTE: Regarding performance
12185// see the NOTE for GetScriptFromScriptData.
12186// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012187RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012188 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012189
12190 ASSERT(args.length() == 1);
12191
12192 CONVERT_CHECKED(String, script_name, args[0]);
12193
12194 // Find the requested script.
12195 Handle<Object> result =
12196 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12197 return *result;
12198}
12199
12200
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012201// Determines whether the given stack frame should be displayed in
12202// a stack trace. The caller is the error constructor that asked
12203// for the stack trace to be collected. The first time a construct
12204// call to this function is encountered it is skipped. The seen_caller
12205// in/out parameter is used to remember if the caller has been seen
12206// yet.
12207static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12208 bool* seen_caller) {
12209 // Only display JS frames.
12210 if (!raw_frame->is_java_script())
12211 return false;
12212 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12213 Object* raw_fun = frame->function();
12214 // Not sure when this can happen but skip it just in case.
12215 if (!raw_fun->IsJSFunction())
12216 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012217 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012218 *seen_caller = true;
12219 return false;
12220 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012221 // Skip all frames until we've seen the caller. Also, skip the most
12222 // obvious builtin calls. Some builtin calls (such as Number.ADD
12223 // which is invoked using 'call') are very difficult to recognize
12224 // so we're leaving them in for now.
12225 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012226}
12227
12228
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012229// Collect the raw data for a stack trace. Returns an array of 4
12230// element segments each containing a receiver, function, code and
12231// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012232RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012233 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012234 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012235 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 HandleScope scope(isolate);
12238 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012239
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012240 limit = Max(limit, 0); // Ensure that limit is not negative.
12241 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012242 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012244
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012245 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012246 // If the caller parameter is a function we skip frames until we're
12247 // under it before starting to collect.
12248 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012249 int cursor = 0;
12250 int frames_seen = 0;
12251 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012252 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012253 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012254 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012255 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012256 // Set initial size to the maximum inlining level + 1 for the outermost
12257 // function.
12258 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012259 frame->Summarize(&frames);
12260 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012261 if (cursor + 4 > elements->length()) {
12262 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12263 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012264 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012265 for (int i = 0; i < cursor; i++) {
12266 new_elements->set(i, elements->get(i));
12267 }
12268 elements = new_elements;
12269 }
12270 ASSERT(cursor + 4 <= elements->length());
12271
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012272 Handle<Object> recv = frames[i].receiver();
12273 Handle<JSFunction> fun = frames[i].function();
12274 Handle<Code> code = frames[i].code();
12275 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012276 elements->set(cursor++, *recv);
12277 elements->set(cursor++, *fun);
12278 elements->set(cursor++, *code);
12279 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012280 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012281 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012282 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012283 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012284 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012285 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012286 return *result;
12287}
12288
12289
ager@chromium.org3811b432009-10-28 14:53:37 +000012290// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012291RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012292 ASSERT_EQ(args.length(), 0);
12293
12294 NoHandleAllocation ha;
12295
12296 const char* version_string = v8::V8::GetVersion();
12297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012298 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12299 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012300}
12301
12302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012303RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012305 OS::PrintError("abort: %s\n",
12306 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012307 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012308 OS::Abort();
12309 UNREACHABLE();
12310 return NULL;
12311}
12312
12313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012315 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012316 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012317 Object* key = args[1];
12318
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012319 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012320 Object* o = cache->get(finger_index);
12321 if (o == key) {
12322 // The fastest case: hit the same place again.
12323 return cache->get(finger_index + 1);
12324 }
12325
12326 for (int i = finger_index - 2;
12327 i >= JSFunctionResultCache::kEntriesIndex;
12328 i -= 2) {
12329 o = cache->get(i);
12330 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012331 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012332 return cache->get(i + 1);
12333 }
12334 }
12335
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012336 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012337 ASSERT(size <= cache->length());
12338
12339 for (int i = size - 2; i > finger_index; i -= 2) {
12340 o = cache->get(i);
12341 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012342 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012343 return cache->get(i + 1);
12344 }
12345 }
12346
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012347 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012348 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012349
12350 Handle<JSFunctionResultCache> cache_handle(cache);
12351 Handle<Object> key_handle(key);
12352 Handle<Object> value;
12353 {
12354 Handle<JSFunction> factory(JSFunction::cast(
12355 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12356 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012357 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012358 // This handle is nor shared, nor used later, so it's safe.
12359 Object** argv[] = { key_handle.location() };
12360 bool pending_exception = false;
12361 value = Execution::Call(factory,
12362 receiver,
12363 1,
12364 argv,
12365 &pending_exception);
12366 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012367 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012368
12369#ifdef DEBUG
12370 cache_handle->JSFunctionResultCacheVerify();
12371#endif
12372
12373 // Function invocation may have cleared the cache. Reread all the data.
12374 finger_index = cache_handle->finger_index();
12375 size = cache_handle->size();
12376
12377 // If we have spare room, put new data into it, otherwise evict post finger
12378 // entry which is likely to be the least recently used.
12379 int index = -1;
12380 if (size < cache_handle->length()) {
12381 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12382 index = size;
12383 } else {
12384 index = finger_index + JSFunctionResultCache::kEntrySize;
12385 if (index == cache_handle->length()) {
12386 index = JSFunctionResultCache::kEntriesIndex;
12387 }
12388 }
12389
12390 ASSERT(index % 2 == 0);
12391 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12392 ASSERT(index < cache_handle->length());
12393
12394 cache_handle->set(index, *key_handle);
12395 cache_handle->set(index + 1, *value);
12396 cache_handle->set_finger_index(index);
12397
12398#ifdef DEBUG
12399 cache_handle->JSFunctionResultCacheVerify();
12400#endif
12401
12402 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012403}
12404
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012406RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012407 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012408 CONVERT_ARG_CHECKED(String, type, 0);
12409 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012410 return *isolate->factory()->NewJSMessageObject(
12411 type,
12412 arguments,
12413 0,
12414 0,
12415 isolate->factory()->undefined_value(),
12416 isolate->factory()->undefined_value(),
12417 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012418}
12419
12420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012421RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012422 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12423 return message->type();
12424}
12425
12426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012427RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012428 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12429 return message->arguments();
12430}
12431
12432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012433RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012434 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12435 return Smi::FromInt(message->start_position());
12436}
12437
12438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012439RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012440 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12441 return message->script();
12442}
12443
12444
kasper.lund44510672008-07-25 07:37:58 +000012445#ifdef DEBUG
12446// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12447// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012448RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012449 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012450 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012451#define COUNT_ENTRY(Name, argc, ressize) + 1
12452 int entry_count = 0
12453 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12454 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12455 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12456#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457 Factory* factory = isolate->factory();
12458 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012459 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012460 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012461#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012462 { \
12463 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012464 Handle<String> name; \
12465 /* Inline runtime functions have an underscore in front of the name. */ \
12466 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012468 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12469 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012471 Vector<const char>(#Name, StrLength(#Name))); \
12472 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012473 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012474 pair_elements->set(0, *name); \
12475 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012476 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012477 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012478 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012479 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012481 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012482 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012483 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012484#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012485 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012486 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012487 return *result;
12488}
kasper.lund44510672008-07-25 07:37:58 +000012489#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490
12491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012492RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012493 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012494 CONVERT_CHECKED(String, format, args[0]);
12495 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012496 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012497 LOGGER->LogRuntime(chars, elms);
12498 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012499}
12500
12501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012502RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012503 UNREACHABLE(); // implemented as macro in the parser
12504 return NULL;
12505}
12506
12507
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012508#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12509 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12510 CONVERT_CHECKED(JSObject, obj, args[0]); \
12511 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12512 }
12513
12514ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12515ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12516ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12517ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12518ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12519ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12520ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12521ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12522ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12523ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12524ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12525ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12527
12528#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530// ----------------------------------------------------------------------------
12531// Implementation of Runtime
12532
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012533#define F(name, number_of_args, result_size) \
12534 { Runtime::k##name, Runtime::RUNTIME, #name, \
12535 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012537
12538#define I(name, number_of_args, result_size) \
12539 { Runtime::kInline##name, Runtime::INLINE, \
12540 "_" #name, NULL, number_of_args, result_size },
12541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012542static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012543 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012544 INLINE_FUNCTION_LIST(I)
12545 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012546};
12547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12550 Object* dictionary) {
12551 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012552 ASSERT(dictionary != NULL);
12553 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12554 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012555 Object* name_symbol;
12556 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012557 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012558 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12559 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012560 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012561 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12562 String::cast(name_symbol),
12563 Smi::FromInt(i),
12564 PropertyDetails(NONE, NORMAL));
12565 if (!maybe_dictionary->ToObject(&dictionary)) {
12566 // Non-recoverable failure. Calling code must restart heap
12567 // initialization.
12568 return maybe_dictionary;
12569 }
12570 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012571 }
12572 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573}
12574
12575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012576const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12577 Heap* heap = name->GetHeap();
12578 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012579 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012580 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012581 int function_index = Smi::cast(smi_index)->value();
12582 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012583 }
12584 return NULL;
12585}
12586
12587
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012589 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12590}
12591
12592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012593void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012594 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012595 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012596 if (failure->IsRetryAfterGC()) {
12597 // Try to do a garbage collection; ignore it if it fails. The C
12598 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012599 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012600 } else {
12601 // Handle last resort GC and make sure to allow future allocations
12602 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012603 isolate->counters()->gc_last_resort_from_js()->Increment();
12604 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012606}
12607
12608
12609} } // namespace v8::internal